How to Build Custom Flexible Rest Architecture in the Salesforce

The Classic Salesforce platform is designed to use the MVC pattern for developing applications and customizing existing functionality. The benefits of server rendering are obvious, but we often need more dynamic in the application. In this case, Rest Services will help us. By default, Salesforce has the following capabilities: Rest API Soap API Remote Actions The platform is also known for its limits. In this case — API Usage Limit. We will get rid of the problems and overcome the limits. Solution The solution is to use the standard Visualforce page with a custom controller to get the result of the request. As a result, we have a page with the following contents: 📄 Copy to clipboard 1 2 3 4 5 6 <apex:page controller="GS_RestApiController" action="{!execute}" contenttype="text/javascript" showHeader="false" sidebar="false"> <apex:outputText value="{!response}" escape="false"/> </apex:page> The method execute from the GS_RestApiController controller will be executed when the page is loaded. The result will be bound into the outputText. Controller Code: 📄 Copy to clipboard 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class GS_RestApiController { private static final String COMMAND_NAME_PARAM = 'command'; private Map<String, String> commandAliasNameMap = new Map<String, String>{ 'test' => 'FirstTest' }; public String response {get; private set;} public GS_RestApiController() { } public void execute() { this.response = getCommand().execute().toJSON(); } private GS_CommandContainer.GS_Command getCommand() { Map<String, String> params = ApexPages.currentPage().getParameters(); String commandName = params.get(COMMAND_NAME_PARAM); if (commandAliasNameMap.containsKey(commandName)) { commandName = commandAliasNameMap.get(commandName); } params.remove(COMMAND_NAME_PARAM); return GS_CommandFactory.create(commandName, params); } } In the controller, we use the command param to execute the command, and we have the map between the command and its alias if necessary. All commands are stored in container class — GS_CommandContainer 📄 Copy to clipboard 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class GS_CommandContainer { public abstract class GS_Command { private Map<String, String> params = new Map<String, String>(); public void setParams(Map<String, String> params) { this.params = params; } public GS_RestResponse execute() { try { Object resultObject = perform(); return new GS_RestResponse(GS_StatusCode.OK, getMessage(), resultObject); } catch (GS_Exception exp) { String message = exp.getMessage() + exp.getStackTraceString(); return new GS_RestResponse(GS_StatusCode.ERROR, message); } catch (Exception exp) { String message = exp.getMessage() + exp.getStackTraceString(); return new GS_RestResponse(GS_StatusCode.ERROR, message); } } public abstract Object perform(); public virtual String getMessage() { return null; } } public class GS_DefaultCommand extends GS_Command { public override Object perform() { return 'This is defult result.'; } public override String getMessage() { return 'This is default message.'; } } Thus, to add a new command, it is necessary simply to extend the base class GS_Command and implement the perform() method where the execution logic will be present. GS_CommandFactory is designed to create an instance of the GS_Command class. 📄 Copy to clipboard 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class GS_CommandFactory { private static final String DOT = '.'; private static final String COMMAND_CONTAINER_NAME = 'GS_CommandContainer'; private static final String DEFAULT_COMMAND_NAME = 'GS_DefaultCommand'; private static final String COMMAND_NAME_TEMPLATE = 'GS_{0}Command'; private static final String COMMAND_NAME_TEMPLATE_WITH_CONTAINER = COMMAND_CONTAINER_NAME + DOT + COMMAND_NAME_TEMPLATE; private static final String DEFAULT_COMMAND_NAME_TEMPLATE_WITH_CONTAINER = COMMAND_CONTAINER_NAME + DOT + DEFAULT_COMMAND_NAME; public static GS_CommandContainer.GS_Command create() { Type commandType = Type.forName(DEFAULT_COMMAND_NAME_TEMPLATE_WITH_CONTAINER); GS_CommandContainer.GS_Command command = (GS_CommandContainer.GS_Command)commandType.newInstance(); return command; } public static GS_CommandContainer.GS_Command create(String commandName, Map<String, String> params) { if(String.isBlank(commandName)) { create(); } String commandClassName = String.format(COMMAND_NAME_TEMPLATE_WITH_CONTAINER, new String[] {commandName}); Type commandType = Type.forName(commandClassName); if(commandType == null) { commandType = Type.forName(DEFAULT_COMMAND_NAME_TEMPLATE_WITH_CONTAINER); } GS_CommandContainer.GS_Command command = (GS_CommandContainer.GS_Command)commandType.newInstance(); command.setParams(params); return command; } } It creates an instance of the required command, depending on the given parameter, or creates an instance of the default class if no such command is found. The example of use is quite simple: 📄 Copy to clipboard 1 var result = $.post('{!Page.RestApi}', {command : 'test'}); The result is: 📄 Copy to clipboard 1 {"result":"FirstTestResult + Params : {}","message":"FirstTestMessage","code":200} When you perform a request without any parameters, the default command is executed. The command name must match the COMMAND_NAME_TEMPLATE template described in GS_CommandFactory, and it is also possible to add the alias and command name to the commandAliasNameMap in the GS_RestApiController. From our side, the architecture is convenient and easily extensible. The source code you can find on GitHub. Nowadays, when Lightning Components is became standard for developing UI. It make less sense. But it can help you if you make custom UI with any JS framework (Angular, React, Vue) or you faced with any problem related with AuraEnabled methods.
How to fix ‘Error: Incorrect parameter type for function ‘ISPICKVAL()’’

You can face a strange issue if you create a formula field in Salesforce and try to use standard ISPICKVAL function with Custom Label because you don’t want to hardcode the values.
How to fix ‘Bad value for restricted picklist field’ error

Users or developers may receive the following error when they attempt to create or update a record in Salesforce: Error: Invalid Data. Review all error messages below to correct your data.‘Bad value for restricted picklist field: PicklistValue’ This error occurs when the picklist field referenced in the error message meets each of the following conditions:
How to merge Accounts in Salesforce

Data quality is one of the most important things you have to watch to get the most out of Salesforce. This helps your sales team to obtain accurate customer data in accordance with various privacy and privacy rules. Salesforce gives you tools for managing duplicates one at a time and across your org, and to track your progress in eliminating duplicates. We will show how to merge Accounts in different interfaces and do not forget about a little Salesforce Hack at the end of the article.
How To Deploy The Project To Salesforce

Problem: We in TrueSolv do not like Apache Ant because we need to configure it using xml. It looks out of date. The question is how to deploy the Salesforce project without Apache Ant? Solution: We can use Metadata API with sfdx.
Modify Fields Onsubmit In Lightning Record Edit Form

Problem Sometimes you need to execute code before submitting the form and set or modify some fields on sObject. For example, you have the following lightning-record-edit-form for Account sObject. Solution To modify some fields you can use onsubmit handler. You can get created/updated sObject from the event object. After the modifications, you need to submit the form. I and our TrueSolv team can help you with any questions related to Salesforce custom development. Contact us.
Working with cookies from Lightning

I want to share with you several ready to use JS functions to working with cookies from Lightning, both Aura Component and Web Components. createCookie function gives an ability to create a cookie with a particular name, value, and time to live.
How To Share Code Between Aura And LWC

Now you can build Lightning components using two programming models: Lightning Web Components, and the original model, Aura Components. Most of the projects consist of Aura Components but more and more developers trying to use LWC for new components. Developers faced with the issue to use common functions in Aura and Lightning Web Components. The solution is pretty simple:
Salesforce and Google Analytics Integration

Track your Salesforce Leads in Google Analytics is easy that you can imagine.