Most systems need to do CRUD on some objects and also query some information. Why not have one endpoint to do it all?I have created a endpoint that can do all that using mapping between systems field and Salesforce fields. System field does not contain any underscores or Salesforce specific syntax like (__c). With that a system can send:
{“name”:”John Doe”, “taxRatePerClient”:20}
And it will be translated to:
{“Name”:”John Doe”, “Tax_Rate_Per_Client__c”:20}
Do CRUD and execute any query
global with sharing class App_Rest_Data {
global with sharing class Post implements App_Rest_Dispatcher.Dispatchable {
private App_Rest_Global_Request_Json requestBody;
global String getURIMapping(){
return App_Rest_Constants.URI_DATA +'/{object}/{operation}';
}
global void setRequestBody(App_Rest_Global_Request_Json requestBody){
this.requestBody = requestBody;
}
global App_Rest_Global_Json execute(Map<String, String> parameters){
App_Rest_Global_Json globalJson = new App_Rest_Global_Json();
String objectName = parameters.get('object');
String operation = parameters.get('operation');
if ('q'.equals(operation)){
globalJson.setResult(Database.query(String.valueOf(((Map<String, Object>)JSON.deserializeUntyped(requestBody.getRequest())).get('query'))));
} else {
Map<String,String> uiFieldNamesForObject = App_Rest_Settings.getModelByObject(objectName);
App_JSON.DynamicModel dynamicModel = new App_JSON.DynamicModel(uiFieldNamesForObject);
dynamicModel.setMapKeysFlag(true);
Type classType = Type.forName(objectName);
SObject sobjectModel = (SObject) classType.newInstance();
sobjectModel = (SObject)dynamicModel.deserialize(requestBody.getRequest(), classType);
fflib_ISObjectUnitOfWork uow = App_Rest_App.UnitOfWork.newInstance();
if ('c'.equals(operation)){
uow.registerNew(sobjectModel);
} else if ('u'.equals(operation)){
uow.registerDirty(sobjectModel);
} else if('d'.equals(operation)){
uow.registerDeleted(sobjectModel);
}
uow.commitWork();
Schema.SObjectType sobjectModelType = Schema.getGlobalDescribe().get(objectName);
fflib_QueryFactory queryFactory = new fflib_QueryFactory(sobjectModelType);
queryFactory.selectFields(uiFieldNamesForObject.keySet());
globalJson.setResult((List<Object>) Database.query(queryFactory.toSOQL()));
}
return globalJson;
}
global override String toString(){
App_Rest_Endpoint.Path path = new App_Rest_Endpoint.Path();
path.setPath(getURIMapping());
App_Rest_Endpoint endpoint = new App_Rest_Endpoint(path);
return JSON.serialize(endpoint);
}
}
}
Testing out CRUD and query operations
@isTest
private class App_Rest_Data_Test {
@isTest(SeeAllData=true) static void testPost() {
Test.setMock(HttpCalloutMock.class, new App_LogEntries_Api_Mock());
RestRequest req = new RestRequest();
RestResponse res = new RestResponse();
User communityUser = App_Global_Test.setupCommunityUserAndLogin();
Test.startTest();
req.requestBody = Blob.valueOf('{"firstName":"Test FirstName","lastName":"Test LastName", "email":"test@mail.com"}');
req.requestURI = '/v1/data/contact/c';
req.httpMethod = 'POST';
RestContext.request = req;
RestContext.response = res;
App_Rest_Dispatcher.doPost();
Test.stopTest();
System.assert(res.responseBody!=null);
System.assertEquals(res.statusCode, 200);
}
@isTest(SeeAllData=true) static void testPatch() {
Test.setMock(HttpCalloutMock.class, new App_LogEntries_Api_Mock());
RestRequest req = new RestRequest();
RestResponse res = new RestResponse();
User communityUser = App_Global_Test.setupCommunityUserAndLogin();
Test.startTest();
Account setupAccount = App_Global_Test.setupAccount();
req.requestBody = Blob.valueOf('{"id":"'+setupAccount.Id+'","name":"Test Update"}');
req.requestURI = '/v1/data/account/u';
req.httpMethod = 'POST';
RestContext.request = req;
RestContext.response = res;
App_Rest_Dispatcher.doPost();
Test.stopTest();
System.assert(res.responseBody!=null);
System.assertEquals(res.statusCode, 200);
}
@isTest(SeeAllData=true) static void testDelete() {
Test.setMock(HttpCalloutMock.class, new App_LogEntries_Api_Mock());
RestRequest req = new RestRequest();
RestResponse res = new RestResponse();
User communityUser = App_Global_Test.setupCommunityUserAndLogin();
Test.startTest();
Account setupAccount = App_Global_Test.setupAccount();
req.requestBody = Blob.valueOf('{"id":"'+setupAccount.Id+'","name":"Test Update"}');
req.requestURI = '/v1/data/account/d';
req.httpMethod = 'POST';
RestContext.request = req;
RestContext.response = res;
App_Rest_Dispatcher.doPost();
Test.stopTest();
System.assert(res.responseBody!=null);
System.assertEquals(res.statusCode, 200);
}
@isTest(SeeAllData=true) static void testQuery() {
Test.setMock(HttpCalloutMock.class, new App_LogEntries_Api_Mock());
RestRequest req = new RestRequest();
RestResponse res = new RestResponse();
User communityUser = App_Global_Test.setupCommunityUserAndLogin();
Test.startTest();
Account setupAccount = App_Global_Test.setupAccount();
req.requestBody = Blob.valueOf('{"query":"Select id from User"}');
req.requestURI = '/v1/data/account/q';
req.httpMethod = 'POST';
RestContext.request = req;
RestContext.response = res;
App_Rest_Dispatcher.doPost();
Test.stopTest();
System.assert(res.responseBody!=null);
System.assertEquals(res.statusCode, 200);
}
}