Generic framework that can be used to implement REST Controllers. Contributions are welcome! Would love to extend the class to include more generic functionality.
REST has become the standard for modern web APIs. This framework provides a standardized approach to building REST Endpoints and provides access to important status codes and a standardized response envelope that follows a popular schema.
The default response schema follows industry guidelines:
{
"data": {},
"messages": [],
"errors": []
}To create a REST Controller for a specific resource, you'll need to create a class that inherits from RESTController.cls and uses the @RestResource annotaion. Below is an example of the basic class setup.
@RestResource(UrlMapping='/accounts')
global class AccountsRESTController extends RESTController {
private static AccountsRESTController controller = new AccountsRESTController();Additionally, you'll need to implement overrides and call them on the standard restful routes. Here's an example of the GET route:
@RestResource(UrlMapping='/accounts')
global class AccountsRESTController extends RESTController {
private static AccountsRESTController controller = new AccountsRESTController();
@HttpGet
global static void getAccounts() {
RestContext.response = controller.getRecords();
}
public override RestResponse getRecords() {
// will need to implement the override method to return the response, something like:
Account accountToReturn = [Select Id From Account];
response.responseBody = new ResponseEnvelope(accountToReturn).getBlob();
return response;
}
}When writing tests, you'll need to write an implementation of the resulting envelope class in that test method in order to parse the results from a JSON Blob into Apex. For the above example it would look something like this:
@IsTest
public with sharing class AccountsRESTControllerTest {
public static AccountResponseEnvelope getAccountResponseEnvelope(RestResponse respose) {
String jsonResponse = response.responseBody.toString();
return (AccountResponseEnvelope) JSON.deserialize(jsonResponse, AccountResponseEnvelope.class);
}
public class AccountResponseEnvelope {
public List<String> messages;
public List<String> errors;
public Account data;
}
public static AccountsResponseEnvelope getAccountsResponseEnvelope(RestResponse respose) {
String jsonResponse = response.responseBody.toString();
return (AccountsResponseEnvelope) JSON.deserialize(jsonResponse, AccountsResponseEnvelope.class);
}
public class AccountsResponseEnvelope {
public List<String> messages;
public List<String> errors;
public List<Account> data;
}
}Using the above methods, your test methods will look something like this:
@IsTest
public with sharing class AccountsRESTControllerTest {
@IsTest
public static void testGet() {
Account account = new Account();
insert account;
RestRequest req = new RestRequest();
req.requestURI = '/services/apexrest/accounts/' + account.Id;
req.httpMethod = 'GET';
req.addHeader('Content-Type', 'application/json');
RestContext.request = req;
RestContext.response = new RestResponse();
AccountsRESTController.getRequest();
RestResponse response = RestContext.response;
AccountResponseEnvelope envelope = getAccountResponseEnvelope(response);
System.assert(envelope.errors.isEmpty(), 'there should be no errors');
System.assert(envelope.messages.isEmpty(), 'there should be no messages');
System.assertEquals(account, envelope.data);
}
}