13

Are there any people who already implemented a custom apex REST api that requires versioning in order not to break existing applications who consume the web service? Do you know any best practices around this?

Use case: a third party application at our customers uses a custom API to access Salesforce. At some point there is a request to add/remove parameters or change the response or the logic of the method. This may impact the third party implementations if they are not updated at the same time.

Thx in advance for your ideas.

  • 2
    Idea is easy -- make a single entry point class, define version as request parameter, define some base interface, that perform your logic, and multiple classes, that corresponds into version and instances of which are constructed in factory – kurunve Jun 21 '17 at 7:51
12
+50

For each version of your Custom Rest API service, you should create a separate Class and a separate endpoint. This implies that you should make the API version a component of the URI. For example /services/apexrest/V1/cases and /services/apexrest/V2/cases. These should live in your code base as two separate Classes.

@RestResource(urlMapping='/V1/cases/*')
global with sharing class REST_cases_v1 {
    @HttpGet
    global static Case[] doGet(){
    //Do some Awesome GET service...
    .
    .
    .
    }
    //Do some other awesome methods....
}

AND

@RestResource(urlMapping='/V2/cases/*')
global with sharing class REST_cases_v2 {
    @HttpGet
    global static Case[] doGet(){
    //Do some even Awesomoar VERSION 2! GET service...
    .
    .
    .
    }
    //Do some other awesome methods....
}

Once Version "next" is released, indicate that version "previous" is deprecated and never touch it again! Over time you can work with your consumers and eventually remove the deprecated versions. I've been versioning APIs like this for a few years and it's worked very well for me.

6

You can add a version parameter in the header of your requests. You can then create an endpoint for each service/method you want to expose and check then which version was called based on the value in the header and execute the code required for that version.

When you have a method in your service where both v1 and v2 are identical but v3 is different then your code in your method might look like this:

if(version == 1 || version == 2){    
//do stuff
}
if(version == 3){
// do other stuff
}
else{
//throw unsupported version error
}
4

Working as an ISV where once a global is packaged and installed the signature can't be changed, I've found this style of working very painful:

@RestResource(urlMapping='/V1/cases/*')
global with sharing class REST_cases_v1 {
    @HttpGet
    global static Case[] doGet(Id someId) {

Essentially the URL mapping, the inputs and the outputs are all fixed. So the only way to evolve is to add another class as John describes which then also means that you or your customer has to ensure that the new class is made visible in all the relevant profiles. (Permission sets can help.)

The pattern I now use instead is this one where the entry point classes once created never need to be replaced and the versioning logic - including the shape of the request and response objects - is entirely under the control of the programmer:

@RestResource(urlMapping='/cases/*')
global with sharing class REST_cases {
    @HttpGet
    global static void doGet() {
        // Parse RestContext.request.requestBody
        // Internal versioning logic based on requests data
        // Serialize and set RestContext.response.responseBody
        // and set RestContext.response.statusCode
    }
}

The parsing/serializing is easy given that JSON.deserialize and JSON.serialize methods are available.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.