Salesforce – Custom REST web service

A lot of salesforce developers never has done a custom webservice. Salesforce has a very powerful REST api but sometimes it’s necessary publish an endpoint to our partners/middleware/applications than should do more business logic than just insert/update or delete a record. With the following template it possible create a custom REST webservice. Let’s analyze the important points:

URL

To make publish a web service it’s necessary have an endpoint with the following part of code you will define the path of the url.

@RestResource(urlMapping = '/account/v/0/*')

The full url it’s https://{{instance}}.salesforce.com/services/apexrest/{{packageNamespace}}/{{path}} the url should be unic for all the org this is why you can not define the same path in two difference apex class, if the two classes are in the same package. If you want to know more about the package, see What is a Package?

REST Method

The followings annotations define the method that should be use in the REST Callout

@HttpDelete
@HttpGet
@HttpPatch
@HttpPost
@HttpPut

Context

The context are two classes of salesforce than contains information about the callout request and response. For example if you need to get the id of a record in the get method, you can use:

RestRequest req = RestContext.request;
String id =req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
RestRequest req = RestContext.request;
RestResponse res = RestContext.response;

Serialization

For the methods POST, PUT, PATCH, the request body it’s automatically serialized using a model the apex class specified in the function parameters Ex: AccountWrapper, this class can contains sObject, primitives objects, or other apex class as parameters.

global class REST_AccountWrapper {
      public String phone;
      public String firstname;
      public String lastname;
      public String street;
      public String email;
      public String city;
      public Date birthdate;
      public String zipcode;
}

TIPS:

    • All the parameters that aren’t included in the body will be serialized as null.
    • Caution because if a Boolean parameter it’s serialized a null and it’s directly inject in a sObject to make a DML will throw and exception.
    • The Date and Datetimes fields should follow the following format YYYY-MM-DDThh:mm:ss.sssZ also are accepted some small format: YYYY-MM-DD, YYYY-MM-DD hh:mm:ss, YYYY-MM-DDThh:mm:ssZ

Error codes

The status code of a response is set automatically if some situations are. To see the full list of the error status you can check the following salesforce documentation here. Keep in mind that it’s not possible set up a custom error code.

Code Examples:

@RestResource(urlMapping = '/account/v/0/*')
global without sharing class Account_v1 {
    @httpPOST
    webservice static AccountWrapper insertAccount(AccountWrapper account) {
        RestResponse res = RestContext.response;
        res.addHeader('Content-Type', 'application/json');
        res.StatusCode = 200;
        try {
            //Place your code logic here
        } catch (Exception e) {
            res.StatusCode = 500;
            return null;
        }
        return account;
    }
    @httpPUT
    webservice static AccountWrapper updateAccount(AccountWrapper account)
        RestResponse res = RestContext.response;
        res.addHeader('Content-Type', 'application/json');
        res.StatusCode = 200;
        try {
        //Place your code logic here
        } catch (Exception e) {
            res.StatusCode = 500;
            return null;
        }
        return account;
    }
    @httpGET
    webservice static AccountWrapper getAccount() {
       RestRequest req = RestContext.request;
       RestResponse res = RestContext.response;
       res.addHeader('Content-Type', 'application/json');
       res.StatusCode = 200;
       try {
           AccountWrapper account = new AccountWrapper();
           //Place your code logic here
       } catch (Exception e) {
           res.StatusCode = 500;
           return null;
       }
       return account;
    }
}
@RestResource(urlMapping='/Account/*')
global with sharing class MyRestResource {

    @HttpDelete
    global static void doDelete() {
        RestRequest req = RestContext.request;
        RestResponse res = RestContext.response;
        String accountId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
        Account account = [SELECT Id FROM Account WHERE Id = :accountId];
        delete account;
    }
  
    @HttpGet
    global static Account doGet() {
        RestRequest req = RestContext.request;
        RestResponse res = RestContext.response;
        String accountId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
        Account result = [SELECT Id, Name, Phone, Website FROM Account WHERE Id = :accountId];
        return result;
    }
  
  @HttpPost
    global static String doPost(String name,
        String phone, String website) {
        Account account = new Account();
        account.Name = name;
        account.phone = phone;
        account.website = website;
        insert account;
        return account.Id;
    }
}
Nous Written by:

3 Comments

  1. October 10, 2015
    Reply

    You can definitely see your skills in the article
    you write. The sector hopes for more passionate writers such as you who aren’t afraid to mention how
    they believe. Always go after your heart.

  2. May 3, 2016
    Reply

    Hello and thank you for this blog is a true inspiration..

Leave a Reply

Your email address will not be published. Required fields are marked *