Skip to content

Commit e1979f4

Browse files
committed
Add ability to make callouts through apex
Users may leverage named credentials to hit secure endpoints
1 parent 64ed5ab commit e1979f4

File tree

10 files changed

+133
-14
lines changed

10 files changed

+133
-14
lines changed

.prettierrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
{
99
"files": "*.{cmp,page,component}",
1010
"options": { "parser": "html","printWidth":120 }
11+
},
12+
{
13+
"files": "*.{cls,trigger,apex}",
14+
"options": { "parser": "apex","printWidth":120 }
1115
}
1216
]
1317
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
** description: Controller for making api calls and sending the response back
3+
**/
4+
5+
public with sharing class APICallController {
6+
@AuraEnabled
7+
public static HttpResponseWrapper makeApiCall(
8+
String endPoint,
9+
String method,
10+
String bodyStr,
11+
Map<String, String> headers
12+
) {
13+
HttpRequest req = new HttpRequest();
14+
req.setEndpoint(endPoint);
15+
system.debug('endpoint ' + endpoint);
16+
req.setMethod(method);
17+
if (method != 'GET') {
18+
req.setBody(bodyStr);
19+
}
20+
if (headers != null) {
21+
for (String key : headers.keySet()) {
22+
req.setHeader(key, headers.get(key));
23+
}
24+
}
25+
HttpResponse resp = new Http().send(req);
26+
system.debug('response ' + resp.getBody());
27+
Map<String, String> respHeaders = new Map<String, String>();
28+
for (String key : resp.getHeaderKeys()) {
29+
respHeaders.put(key, String.valueOf(resp.getHeader(key)));
30+
}
31+
return new HttpResponseWrapper(resp.getBody(), resp.getStatusCode(), respHeaders);
32+
}
33+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>48.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>

force-app/main/default/classes/DynamicSOQLDMLControllerTest.cls

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ public with sharing class DynamicSOQLDMLControllerTest {
66
insert a;
77
a.Phone = '432424';
88
Account[] recordsToUpdate = new List<Account>{ a };
9-
DynamicSOQLDMLController.executeDml('update', recordsToUpdate, null, null);
9+
DynamicSOQLDMLController.executeDml('update', JSON.serialize(recordsToUpdate), 'Account');
1010
a = [SELECT Phone FROM Account WHERE Id = :a.Id];
1111
System.assertEquals('432424', a.Phone);
1212
}
@@ -16,11 +16,8 @@ public with sharing class DynamicSOQLDMLControllerTest {
1616
// we won't test fetching cmdt
1717
DynamicSOQLDMLController.getJSFromCmdt('Account');
1818
String acctString = '[{"attributes":{"type":"Account"},"Name":"Test Account"}]';
19-
DynamicSOQLDMLController.executeDml('insert', null, acctString, 'Account');
20-
System.assertEquals(
21-
1,
22-
[SELECT ID FROM Account WHERE Name = 'Test Account'].size()
23-
);
19+
DynamicSOQLDMLController.executeDml('insert', acctString, 'Account');
20+
System.assertEquals(1, [SELECT ID FROM Account WHERE Name = 'Test Account'].size());
2421
}
2522

2623
@isTest
@@ -34,7 +31,7 @@ public with sharing class DynamicSOQLDMLControllerTest {
3431
accountsToUpdate.add(a1);
3532

3633
String acctString = JSON.serialize(accountsToUpdate);
37-
DynamicSOQLDMLController.executeDml('upsert', null, acctString, 'Account');
34+
DynamicSOQLDMLController.executeDml('upsert', acctString, 'Account');
3835
System.assertEquals(2, [SELECT ID FROM Account].size());
3936
a = [SELECT Phone FROM Account WHERE Id = :a.Id];
4037
System.assertEquals('432343', a.Phone);
@@ -44,9 +41,7 @@ public with sharing class DynamicSOQLDMLControllerTest {
4441
public static void testSoql() {
4542
Account a = new Account(Name = 'Test Account');
4643
insert a;
47-
Account[] acctsResult = DynamicSOQLDMLController.executeSoqlQuery(
48-
'Select Name from Account'
49-
);
44+
Account[] acctsResult = DynamicSOQLDMLController.executeSoqlQuery('Select Name from Account');
5045
System.assertEquals(1, acctsResult.size());
5146
System.assertEquals('Test Account', acctsResult[0].Name);
5247
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
public with sharing class HttpResponseWrapper {
2+
@AuraEnabled
3+
public String body;
4+
@AuraEnabled
5+
public Integer statusCode;
6+
@AuraEnabled
7+
public Map<String, String> headers;
8+
9+
public HttpResponseWrapper(String body, Integer statusCode, Map<String, String> headers) {
10+
this.body = body;
11+
this.statusCode = statusCode;
12+
this.headers = headers;
13+
}
14+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>48.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<template>
2+
3+
</template>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { api } from "lwc";
2+
import makeApiCall from "@salesforce/apex/APICallController.makeApiCall";
3+
4+
export default class HttpRequest {
5+
endPoint = "";
6+
method = "GET";
7+
body = null;
8+
headers = {};
9+
10+
@api
11+
setEndpoint(val) {
12+
this.endPoint = val;
13+
}
14+
15+
@api
16+
setMethod(val) {
17+
this.method = val;
18+
}
19+
20+
@api
21+
setBody(val) {
22+
this.body = val;
23+
}
24+
25+
@api
26+
addHeader(key, value) {
27+
if (typeof value !== "string")
28+
throw "You may only set string values for headers";
29+
this.headers[key] = value;
30+
}
31+
32+
@api
33+
clear() {
34+
this.endPoint = "";
35+
this.method = "GET";
36+
this.body = null;
37+
this.headers = {};
38+
}
39+
40+
@api
41+
async send() {
42+
let resp = await makeApiCall({
43+
endPoint: this.endPoint,
44+
method: this.method,
45+
bodyStr: this.body ? JSON.stringify(this.body) : "",
46+
headers: this.headers
47+
});
48+
return resp;
49+
}
50+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>48.0</apiVersion>
4+
<isExposed>false</isExposed>
5+
</LightningComponentBundle>

force-app/main/default/lwc/jsButtonLwc/jsButtonLwc.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import executeSoql from "@salesforce/apex/DynamicSOQLDMLController.executeSoqlQu
44
import executeDml from "@salesforce/apex/DynamicSOQLDMLController.executeDml";
55
import getSObjectType from "@salesforce/apex/DynamicSOQLDMLController.getSObjectTypeFromId";
66
import { ShowToastEvent } from "lightning/platformShowToastEvent";
7+
import HttpRequest from "c/httpRequest";
78

89
const REGEX_SOQL = "\\|\\|\\s?(select\\s+[^|]+)\\s?\\|\\|";
910
const REGEX_UPDATE = "\\|\\|\\s?update\\s([^|;]+);?\\s*\\|\\|";
@@ -16,6 +17,8 @@ export default class JsButtonLwc extends LightningElement {
1617
@api recordId;
1718
_notifiedParent = false;
1819

20+
httpRequest = new HttpRequest();
21+
1922
renderedCallback() {
2023
if (!this._notifiedParent)
2124
this.dispatchEvent(new CustomEvent("initcomplete"));
@@ -26,8 +29,8 @@ export default class JsButtonLwc extends LightningElement {
2629
if (!this.js && this.cmdtName) {
2730
let js = await fetchJSFromCmdt({ cmdtName: this.cmdtName });
2831
await this.runJS(js);
29-
}else if(this.js){
30-
await this.runJS(this.js)
32+
} else if (this.js) {
33+
await this.runJS(this.js);
3134
}
3235
}
3336

@@ -47,7 +50,7 @@ export default class JsButtonLwc extends LightningElement {
4750

4851
async executeDml(dmlType, records, sObjectType) {
4952
try {
50-
if(records && !Array.isArray(records)){
53+
if (records && !Array.isArray(records)) {
5154
records = [records];
5255
}
5356
if (!sObjectType)
@@ -93,7 +96,9 @@ export default class JsButtonLwc extends LightningElement {
9396
new RegExp(REGEX_INSERT_UPSERT, "gi"),
9497
"await this.executeDml('$1',$3,'$2');"
9598
);
96-
let op = await (Function("recordId", `return (async ()=>{${js}})()`).bind(this))(this.recordId);
99+
let op = await Function("recordId", `return (async ()=>{${js}})()`).bind(
100+
this
101+
)(this.recordId);
97102
return op;
98103
}
99104
}

0 commit comments

Comments
 (0)