Apex API programming
Apex is a proprietary, object-oriented programming language used by Salesforce developers to execute flow and transaction control statements on the Salesforce platform. It is a powerful, strongly-typed language that looks and behaves like Java.
🛠️ Setting up your environment
Before you can program or deploy, you need to connect your local development environment (Visual Studio Code) to your Salesforce Org.
Watch: How to Connect VS Code to Salesforce Org This video provides a step-by-step guide on authorizing an org and setting up your project.
How to Connect VS Code to Salesforce Org
💻 Apex API Programming
Apex allows developers to:
- Implement complex business logic: Custom validations and transaction control.
- Create custom Web Services: Expose REST or SOAP endpoints.
- Write Triggers: Execute code on database events (
insert,update,delete).
For example, a developer might create a REST service using the @RestResource annotation to enable a web application to retrieve and update a customer's service requests quickly.
🚀 How to deploy updates to the Salesforce Production Environment
Deploying updates involves moving metadata from a lower environment (Sandbox) to Production. While you can deploy an entire project, developers often need to deploy specific files to save time and reduce risk.
Use the following command to deploy specific Apex classes within your project:
sf deploy metadata -m "ApexClass:ContactManager" -m "ApexClass:ContactManagerTest" --test-level RunSpecifiedTests --tests ContactManagerTest
Here is the breakdown of what this command does:
-
sf deploy metadata: This initiates the deployment process focusing on specific metadata components rather than the whole source directory. -
-m "ApexClass:ContactManager": The-mflag stands for Metadata. This tells the CLI to only deploy the Apex Class file named "ContactManager". -
-m "ApexClass:ContactManagerTest": We use the flag again to include the corresponding Test Class. It is best practice to always deploy the code and its test together. -
--test-level RunSpecifiedTests: This is a crucial efficiency flag. By default, production deployments run all local tests. This flag tells Salesforce: "Do not run every test in the system; only run the ones I list." -
--tests ContactManagerTest: This explicitly lists the test class to execute. If this test passes (and covers enough lines of code), the deployment succeeds.
Why use this? If your organization has thousands of tests that take 2 hours to run, using RunSpecifiedTests allows you to deploy a hotfix in minutes by only validating the relevant code.
📝 Code Examples
Below are examples of the classes referenced in the command above.
- The REST Resource Class (
ContactManager.cls)
This class uses the @RestResource annotation to define the endpoint URL. It includes a GET method to retrieve data and a POST method to create new records.
@RestResource(urlMapping='/Contacts/*')
global with sharing class ContactManager {
// HTTP GET: Retrieve a Contact by ID from the URL
// Endpoint: https://your-instance.salesforce.com/services/apexrest/Contacts/<ContactId>
@HttpGet
global static Contact getContactById() {
RestRequest req = RestContext.request;
// Grab the contactId from the end of the URL
String contactId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
Contact result = [SELECT Id, Name, Email, Phone FROM Contact WHERE Id = :contactId];
return result;
}
// HTTP POST: Create a new Contact
// Endpoint: https://your-instance.salesforce.com/services/apexrest/Contacts/
@HttpPost
global static ID createContact(String lastName, String firstName, String email, String phone) {
Contact thisContact = new Contact(
LastName = lastName,
FirstName = firstName,
Email = email,
Phone = phone
);
insert thisContact;
return thisContact.Id;
}
}
- The Test Class (
ContactManagerTest.cls)
Testing REST services in Apex requires a specific step: mocking the RestContext. You must manually construct the Request and Response objects within the test method so the code has a context to run against.
@isTest
private class ContactManagerTest {
@testSetup
static void makeData() {
Contact c = new Contact(LastName='Test', FirstName='Unit', Email='test@example.com');
insert c;
}
@isTest
static void testGetContactById() {
// 1. Query the record created in testSetup
Contact c = [SELECT Id FROM Contact LIMIT 1];
// 2. Set up the RestContext
RestRequest req = new RestRequest();
RestResponse res = new RestResponse();
// Simulate the URL structure defined in the main class
req.requestURI = '/services/apexrest/Contacts/' + c.Id;
req.httpMethod = 'GET';
// Assign the mock request to the context
RestContext.request = req;
RestContext.response = res;
// 3. Call the method
Test.startTest();
Contact result = ContactManager.getContactById();
Test.stopTest();
// 4. Assertions
System.assert(result != null);
System.assertEquals('Test', result.LastName);
}
@isTest
static void testCreateContact() {
Test.startTest();
// Call the POST method directly
ID thisContactId = ContactManager.createContact('Doe', 'John', 'john.doe@example.com', '555-1234');
Test.stopTest();
// Verify record exists
System.assert(thisContactId != null);
Contact c = [SELECT LastName FROM Contact WHERE Id = :thisContactId];
System.assertEquals('Doe', c.LastName);
}
}
Key Concepts in this Example
-
@RestResource(urlMapping='/Contacts/*'): This exposes the class at the base URL/services/apexrest/Contacts/. -
global: Methods exposed as Web Services must be defined as global. -
RestContext: A system class that allows your code to access the incoming HTTP Request (RestContext.request) and the outgoing Response (RestContext.response). -
Dynamic ID Parsing: In the GET method, we parse the URL to find the ID
(substring(req.requestURI.lastIndexOf('/')+1)). This mimics standard REST behavior (e.g.,GET /Contacts/003xxxxxxxxxxxx).
Summary
Developing on Salesforce requires a dual mastery: Apex API programming for crafting robust, custom business logic and effective deployment strategies for moving those solutions safely to the Production environment.
Key Takeaways for Success
- Code Quality is Paramount: Always adhere to Salesforce best practices, especially writing bulkified code to handle large data volumes efficiently.
- Testing is Non-Negotiable: Deployment hinges on your Apex Test Classes. Achieving the minimum 75% code coverage is mandatory for Production deployment, but striving for 100% ensures stability.
-
Embrace the CLI: Using the Salesforce CLI (
sf) for targeted, automated deployments (like using--test-level RunSpecifiedTests) offers speed and reliability far superior to traditional Change Sets.
Top comments (1)
Thank you! It was helpful