Apex is the core language for customizing business logic on the Salesforce Platform and for integrating with third-party systems. Whenever you need to expose platform data or custom logic to an external system, one of your options is to create a custom Apex REST endpoint. In this post, we’ll discuss the use cases for implementing custom Apex REST endpoints, and we’ll share tips on how to implement and test them.
Understand use cases and alternatives to custom REST endpoints
Custom Apex REST endpoints are quite powerful because they give you full control over the business logic for your integration. However, it’s easy to overlook the fact that your custom endpoint code induces a maintenance cost, and that there are a number of alternatives that do not require code on the Salesforce side.
Salesforce has a rich set of APIs that may cover your integration needs:
- The REST API is the most flexible API. Among other things, it exposes CRUD operations on records and queries over other entities, such as data model objects or limits. However, requests to this API operate outside of transactions, and this can be a problem when you need to chain write operations in the context of an integration. For example, if you need to update three records and the second request fails, you must implement a manual rollback strategy to cancel the first operation.
- The Composite API is a great addition to the REST API. It allows you to chain REST API calls within a transactional context thanks to an
allOrNoneflag (see docs). Note that changes can be rolled back in case of errors. Additionally, it supports chained operations for creating linked records, such as an Account, an Opportunity, and a Contact, with a single request.
- The UI API is great for retrieving both data and metadata associated with objects and records in single API calls. It also supports CRUD operations on individual records.
- The GraphQL API (Beta as of Summer ’22 release) is the latest addition to the API family. It leverages standard GraphQL query language and allows you to run queries on the UI API. Unlike the other APIs, the GraphQL API is read only.
Read the documentation for those APIs and explore them using tools like the Salesforce Platform APIs collection for Postman. Then, if your use case requires some custom business logic, such as calculation using multiple records, and a series of CRUD operations that APIs cannot cover, you can implement a custom Apex REST endpoint.
Expose a custom REST endpoint with Apex
Implement a custom REST endpoint
The first thing that you need to do is to create a
global Apex class annotated with
@RestResource (see docs) and a
urlMapping property. This lets you expose your resource using a URL pattern such as:
Note the use of an optional
* wildcard character in our
urlMapping value. This would capture all of the following HTTP requests URLs where
MY_DOMAIN_HOST is the My Domain hostname:
Important: Unlike Apex, URLs are case-sensitive. As a general REST best practice, keep URLs in lowercase.
Now that you’ve declared a REST resource class, you need to create one or more Apex methods to capture requests from various HTTP methods. To do so, you’ll need to declare static Apex methods annotated by one of these:
|Annotation||HTTP method||Conventional REST usage|
||Removing a resource.|
||Reading a resource.|
||Updating a resource. The difference with PUT is that PATCH accepts a partial copy of the resource for an update.|
||Creating a new resource.|
||Updating a resource. The difference with PATCH is that PUT expects a full copy of the resource for an update.|
For example, the method below captures all incoming GET requests for our REST resource. The method’s name has no importance, but it is recommended that you at least mention the HTTP method to simplify tests (spoiler: you’ll be calling the method in your tests).
If needed, you can add the
@ReadOnly annotation (see docs) to your method. This doubles the maximum number of returned rows to 100,000 for SOQL queries that run in this method. As a side note, the
@ReadOnly annotation isn’t limited to REST endpoint methods, it’s also available for SOAP Web services and the Schedulable interface.
Now that you have the method signature, the next step is to implement its body. To do so, we rely on the
System.RestContext class (see docs) to capture the details of the incoming request as an instance of
System.RestRequest (see docs).
With this, here’s how the implementation of a “Hello, world” GET request would look:
In our example, the method returns a string, but you can work with any object type or binary content. Whenever you specify a return type for the Apex method, the Salesforce Platform serializes its value as JSON in the body of the response.
If you want more control over the response, you can work with a void method and pass the result to an instance of
System.RestResponse (see docs) that you retrieve from the
RestContext. This lets you control the return type, the headers, and the HTTP status code.
Here’s the same “Hello, world” example using the
Another subtlety that’s worth mentioning is that if your request has a JSON body, you can automatically extract values from it thanks to Apex method parameters. For instance, if your request body uses this format:
You can capture parameter values with this Apex method signature:
Now that you know how to implement a custom Apex REST endpoint, let’s look at how you can write tests for it.
Write Apex tests for a custom REST endpoint
When testing your endpoint, you can simply fake the
RestContext object to pass in your test values. For instance, this is a test that covers our “Hello, world” example. Note how we fake the request URI and HTTP method and directly invoke the method that would be exposed as an HTTP resource.
When testing a void endpoint method that uses
RestContext.response instead of a return type, you can check the server’s response from the test context:
This concludes our post on custom Apex REST endpoints. You should now have a good sense of the alternatives to writing your own endpoint, and if it comes to this, how you can implement one with the related tests. Make sure to check our Apex Recipes sample app for examples of Apex REST resources and their associated tests. Always remember that code that you don’t write is code that you don’t have to maintain.
Custom Apex endpoints resources
- codeLive video on YouTube: Writing Apex REST Services (and When Not To)
- Apex Developer Guide: Exposing Apex Classes as REST Web Services
- Sample application: Apex Recipes
- Trailhead: Apex Integration Services (see last unit “Apex Web Services”)
Salesforce API resources
- REST API Developer Guide
- Composite API documentation
- UI API Developer Guide
- GraphQL API Developer Guide (Beta as of Summer ’22 release)
- Salesforce Platform APIs collection for Postman
About the author
Philippe Ozil is a Principal Developer Advocate at Salesforce where he focuses on the Salesforce Platform. He writes technical content and speaks frequently at conferences. He is a full stack developer and enjoys working on DevOps, robotics, and VR projects. Follow him on Twitter @PhilippeOzil or check his GitHub projects @pozil.