Apex REST services in Summer’ 11

One of the cool new Pilot features in the upcoming Summer' 11 release is Apex REST services. Dave Carroll and yours truly recently hosted a webinar highlighting some of the interesting Platform features in the Summer' 11 release (including Apex REST services) and you can watch a full recording of the webinar here. If you're only interested in Apex REST, jump to this point of the recording.

I'm in the process of posting all the sample code that was demoed during the webinar and after Dynamic Visualforce Components, it's now time to look at Apex REST services.

1) What is Apex REST? This is a new Pilot feature in Summer' 11 (Pilot means that you will need to contact Salesforce support to enable this feature in an Org) that allows you to expose any Apex class as a RESTful service for external clients to invoke. If you're not familiar with the REST protocol, the official Wikipedia entry is a good starting point. At its simplest form, REST (or 'Representational State Transfer') uses a combination of the URL and the HTTP 'verb' or method (GET, POST, PATCH, DELETE etc) to perform actions on certain resources. You can look at the Force.com REST API as one example of a RESTful API.

2) Authentication and data formats – All clients have to authenticate before accessing any Apex REST service that you define. They can do so using either OAuth 2.0 or username/password authentication. In either case, the client has to set the authorization HTTP header with the appropriate value (an OAuth access token or a sessionid acquired via a 'login' call to the Force.com SOAP API). Apex REST supports both JSON and XML data formats.

3) How does this feature compare to Apex SOAP services? This new feature is similar to Apex SOAP services which allow you to expose Apex code as custom SOAP/WSDL web services. The difference of course is that with Apex REST, the client gets to invoke your custom logic using the more lightweight REST protocol vs the more verbose SOAP/WSDL protocols. For example, since REST only requires a simple HTTP library to invoke/consume, mobile or Web 2.0 clients may find it easier to consume an Apex REST service vs an Apex SOAP service. In addition, the JSON data format that Apex REST supports is especially well suited for Javascript clients. You could of course structure your custom business logic such that it is exposed as both SOAP and REST services. The SOAP service may be consumed by a backend system/middleware client while the REST service may be consumed by mobile/Web 2.0 clients.

4) How does this feature compare to the Force.com REST API? The Force.com REST API also provides access to Force.com data via a RESTful protocol (as does the Force.com Bulk API for that matter). Apex REST allows developers to in effect create their own custom implementation of a RESTful service if the standard Force.com REST API does not meet their needs. For example, if you wanted to implement and expose custom transactions you could do so with an Apex REST service. You could also use Apex REST to expose a customized RESTful interface to clients of your application that is different from the standard Force.com REST API structure/conventions. 

5) Let's not forget API Limts. Every client invocation of an Apex REST service counts against the respective API request limit for the Org (similar to Apex SOAP).

6) Can I now have some sample code please? Ask and you shall receive. The webinar demo included an Android mobile client invoking a custom Apex REST service to insert a new Case record in the Force.com database. Along with the Case information, the Android client also had to sent data for two related child Custom Objects – 'Labor' and 'Parts & Expenses'. A custom service was required to implement a transaction requirement – insert the parent Case record and the associated child records in a all-or-nothing transaction. Here is the Apex class that exposes that custom logic as an Apex REST service.

@RestResource(urlMapping='/CaseManagement/*')
global with sharing class CaseManagementRESTSvc {
@HttpGet
global static Case getCaseRecord(RestRequest req, RestResponse res) {
String caseNum = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
Case c = CustomCaseMgmt.getCase(caseNum);
return c;
}
@HttpPost
global static Case createCaseRecord(RestRequest req, RestResponse res,
Integer acctNumber,
String subject,
String priority,
String description,
Double labor_rate,
Double labor_timeWorked,
String pe_partNumber,
Integer pe_quantity,
Double pe_unitPrice) {
CompositeCaseRecord compositeCaseRec = new CompositeCaseRecord();
compositeCaseRec.acctNumber = acctNumber;
compositeCaseRec.subject = subject;
compositeCaseRec.priority = priority;
compositeCaseRec.description = description;
compositeCaseRec.labor_rate = labor_rate;
compositeCaseRec.labor_timeWorked = labor_timeWorked;
compositeCaseRec.pe_partNumber = pe_partNumber;
compositeCaseRec.pe_quantity = pe_quantity;
compositeCaseRec.pe_unitPrice = pe_unitPrice;
Case c = CustomCaseMgmt.createCase(compositeCaseRec);
return c;
}
@HttpDelete
global static void deleteCaseRecord(RestRequest req, RestResponse res) {
String caseNum = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
CustomCaseMgmt.deleteCase(caseNum);
}
}

Lets now break down the code. First off, the new '@RestResource' annotation marks a global Apex class as being available as a REST service (similar to how the 'webservice' keyword marks a class as a SOAP service). The 'urlMapping' value that you define corresponds to the URL that your clients will invoke to access the service. The mapping you define is relative to 'https://<instance>.salesforce.com/services/apexrest/' – i.e the client would have to use the 'https://instance.salesforce.com/services/apexrest/CaseManagement' URL to invoke the above service.

You use the '@HttpGet', '@HttpPost' etc annotations to mark which method maps to the respective HTTP verb. In the above example, the 'createCaseRecord' method will be invoked if the client makes a POST request to the service URL (which is what the Android client does), the 'getCaseRecord' method will be invoked if the client makes a GET request and so on. Java developers who've used the Jersey implementation of the JAX-RS (JSR 311) spec may find the syntax familiar.

As you can see from the example above, the actual business logic for creating the Case record and its associated child records is encapsulated in a separate 'CustomCaseMgmt' class. There are two reasons why this is a general best practice. One, if you abstract the logic in a separate class, you can also easily expose it as SOAP service if you so wish. Second and more importantly, the 'CustomCaseMgmt' class is defined with the 'with sharing' keyword. Like Apex SOAP services, Apex methods that are exposed as REST services run under general Sys Admin privileges and do not observe object permissions, field-level security or sharing rules. You could therefore inadvertently let uses access or manipulate data that they should otherwise not be allowed to. You can avoid this by encapsulating all business logic in a separate 'with sharing' class and then invoke that class from the Apex REST service class.  

7) Key implementation considerations: A couple of important consideration to keep in mind with Apex REST. First and foremost, remember that it is a Pilot feature in Summer 11 and so you'll need to contact Salesforce support to have it enabled. Other important considerations:

  • The supported parameter and return types for Pilot are Primitives, SObjects and List/Maps of the two.
  • The name and order of the method parameters is very important. One of the webinar slides has more detail about what this means for clients of an Apex REST service.

8) RestRequest and RestResponse classes: Gimlet eyed readers may have have noticed the RestRequest and RestResponse classes defined as method parameters in the sample above. The official Apex REST documentation will have additional details about those classes, but in brief, you can use those classes to get and set Cookie and HTTP Header information in the REST request and response messages. Those classes also let you access the incoming request (RestRequest.requestBody) and outgoing response (RestResponse.responseBody) data as Apex Blobs. In other words, instead of defining method parameters and return types and having the Force.com platform automatically deserialize the incoming JSON/XML request into your method parameters or automatically serialize the return type (if any), you can choose to use the respective Blob representation to perform your own custom serialization/deserialization logic. If you combine RestRequest and RestResponse with other method parameters and return types (as shown in the sample above), the platform will attempt the automatic serialization/deserialization and no Blob data will be available in the two classes.

Apex REST gives you the ability to define a custom RESTful interface to your application and I think that developers will love the simplicity and power of this new feature. As always, comments and questions are welcome.

Published
May 18, 2011
Topics:

Leave your comments...

Apex REST services in Summer’ 11