A practical reference for Apex development on Salesforce Service Cloud: queries, triggers, HTTP callouts, scheduled jobs, and deployment utilities. This page covers the patterns that come up most in backend and integration work.
Preparation
⚠️ All external endpoints must be whitelisted in Setup > Security > Remote Site Settings before any callout will succeed.
Walkthrough
SOQL, DML & Dates
// Query
List<Account> accounts = [SELECT Id, Name FROM Account];
System.debug('size: '+accounts.size());
// Loop
for(Account account : accounts){
throw new IllegalArgumentException('Test'); // Exception class is abstract. Use Exceptions.SystemException, ApplicationException
}
// Insert / Update
Account a = new Account(Name='');
insert a;
a.Name = 'New name';
update a;
// Dates
datetime nowDatetime = datetime.now(); // for saleItemGeneratedId PLOCRM-21
string nowDate = nowDatetime.format('yyyyMMdd');
string nowTime = nowDatetime.format('HHmmss');Parent-child SOQL request (and datetime)
Datetime dtFrom = DateTime.newInstance(2021, 09, 01, 0, 0, 0);
List<Sale__c> sales = [
SELECT
Id, Name, Locale__c,
(
SELECT Id, Quantity__c, Product__c, Amount__c
FROM Ticket_Lines__r
WHERE Quantity__c>0 AND Amount__c>0
)
FROM Sale__c
WHERE Purchase_Date__c > :dtTo
];
for(Sale__c sale: sales){
System.debug(sale.Ticket_Lines__r.size()+' lines');
}Triggers
trigger MyrosCaseTrigger on Case (
before insert, before update, before delete,
after insert, after update, after delete, after undelete
) {
if(Trigger.Isupdate){
MyrosCaseHelper.process(Trigger.new);
}
}HTTP Callouts
GET Request
HttpRequest request = new HttpRequest();
request.setEndpoint('https://jsonplaceholder.typicode.com/users');
request.setMethod('GET');
HttpResponse response = new Http().send(request);
List<Object> records = (List<Object>) JSON.deserializeUntyped(response.getBody());
for (Object record : records) {
Map<String, Object> mapped = (Map<String, Object>) record;
String id = (String) mapped.get('id');
}POST to SOAP API (e.g. Adobe Campaign)
Update broadlog statuses in Adobe Campaign from Salesforce:
HttpRequest request = new HttpRequest();
request.setEndpoint('https://xxx.neolane.net/nl/jsp/soaprouter.jsp');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/xml');
request.setHeader('SOAPAction', 'xtk:persist#WriteCollection');
request.setBody(
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:xtk:session">' +
'<soapenv:Header/>' +
'<soapenv:Body>' +
'<urn:WriteCollection>' +
'<urn:sessiontoken>user_name/pass_word</urn:sessiontoken>' +
'<urn:domDoc>' +
'<broadLogRcp-collection xtkschema="nms:broadLogRcp">' +
'<broadLogRcp id="129106000" status="5" _operation="update" _key="@id" eventDate="2018-12-25 11:05:59"/>' +
'<broadLogRcp id="129117000" status="4" _operation="update" _key="@id" eventDate="2018-12-25 11:05:59"/>' +
'</broadLogRcp-collection>' +
'</urn:domDoc>' +
'</urn:WriteCollection>' +
'</soapenv:Body>' +
'</soapenv:Envelope>'
);
HttpResponse response = new Http().send(request);
System.debug(response.getBody());POST to REST API (e.g. Marketing Cloud)
Two-step: authenticate, then call. See also Marketing Cloud REST API.
// Step 1 — Authenticate
HttpRequest authRequest = new HttpRequest();
authRequest.setEndpoint('https://xxx.auth.marketingcloudapis.com/v2/token');
authRequest.setMethod('POST');
authRequest.setHeader('Content-Type', 'application/json');
authRequest.setBody('{"grant_type":"client_credentials","client_id":"xxx","client_secret":"xxx","account_id":"xxx"}');
HttpResponse authResponse = new Http().send(authRequest);
Map<String, Object> authBody = (Map<String, Object>) JSON.deserializeUntyped(authResponse.getBody());
String accessToken = (String) authBody.get('access_token');
// Step 2 — Send transactional email
HttpRequest request = new HttpRequest();
request.setEndpoint('https://xxx.rest.marketingcloudapis.com/messaging/v1/email/messages/');
request.setMethod('POST');
request.setHeader('Authorization', 'Bearer ' + accessToken);
request.setHeader('Content-Type', 'application/json');
request.setBody(
'{"definitionKey":"Auto_WW_DoubleOptinQRCode","recipients":[{"contactKey":"0034H00002ZiYo5QAF","to":"[email protected]","attributes":{"FirstName":"John","LastName":"Doe"}}]}'
);
HttpResponse response = new Http().send(request);
System.debug(response.getBody());Scheduled Jobs
Find running jobs in Setup > Environments > Jobs > Scheduled Jobs.
global class MyrosSchedule implements Schedulable {
global void execute(SchedulableContext ctx) {
// process
}
}Schedule from the Anonymous Window:
// Seconds Minutes Hours Day Month Weekday Year
String cron = '0 0 1 * * ? *'; // daily at 01:00
// → https://www.freeformatter.com/cron-expression-generator-quartz.html
String jobId = System.schedule('JobName', cron, new MyrosSchedule());
System.debug(jobId);Stop job from Setup > Scheduled Jobs > Delete or programmatically:
System.abortJob(jobId);Validation & troubleshooting
Any Apex Class deployed to production needs to be at least 80% covered by Unit Tests.
Trigger unit test
@isTest
public with sharing class MyrosCaseTriggerTest {
@isTest private static void test() {
Case c = new Case(Subject='TestCase');
insert c;
List<Case> createdCases = [SELECT Id FROM Case WHERE Subject = 'TestCase'];
System.assertEquals(1, createdCases.size());
}
}Callout mock for unit tests
@isTest
global class MyrosCalloutMock implements HttpCalloutMock {
global HTTPResponse respond(HTTPRequest request) {
HttpResponse response = new HttpResponse();
response.setHeader('Content-Type', 'application/json');
response.setBody('[{"id": 1}]');
response.setStatusCode(200);
return response;
}
}Going further
Delete Apex from Production
Production orgs block direct deletion of Apex. Deploy a destructiveChanges.xml via Workbench under Migration > Deploy.
package.xml
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://soap.sforce.com/2006/04/metadata">
<version>30.0</version>
</package>destructiveChanges.xml
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>Class1</members>
<members>Class2</members>
<members>Class3</members>
<name>ApexClass</name>
</types>
<version>30.0</version>
</Package>Zip both files and deploy.
Related
- Marketing Cloud REST API
- Acquisition page: an Apex controller and its test class in a real use case