3

I have created a very simple REST service to convert a lead:

@RestResource(urlMapping='/ConvertLeadFromApp/*')
global with sharing class RESTLeadConvertController {

    @HttpGet
    global static Lead getConvertedLead() {
        String leadId = RestContext.request.params.get('leadId');       
        Database.LeadConvert lc = new Database.LeadConvert(); 
        lc.setLeadId(leadId);
        lc.setDoNotCreateOpportunity(true);
        LeadStatus convertstatus = [select Id, MasterLabel from LeadStatus where IsConverted = true limit 1];
        lc.setConvertedStatus(convertStatus.MasterLabel); 
        Database.LeadConvert[] lcArray = new Database.LeadConvert[] {lc}; 
        Database.LeadConvertResult[] results = Database.convertLead(lcArray);   
        Lead result = [SELECT Id, email, status, isConverted, convertedAccountId, convertedContactId FROM Lead WHERE Id = :leadId];
        return result;
    }   
}

I've been looking at the best way to provide error handling and send back a success or failure to the consumer. What is the best practice on error handling design for a REST service?

12

You should use standard http status codes.

You can set the status code on RestContext.response anytime before you return.

Salesforce will automatically handle most of these. For example, you don't need to handle 401 UNAUTHORIZED as if the request fails authentication, your code will never even be executed.

However, you typically will want to handle additional checks in your own code.

Also (IMO) you should return the same standard error response that Salesforce uses for MOST their data API endpoints (composite API is one exception):

[
  { errorCode: 'NOT_FOUND', message: 'Could not find a match for URL...' }
]

This makes it much easier for any consuming clients to handle errors.

Another point to consider is that you should avoid using the automatic serialization of return objects and instead set your own JSON response.

This allows you to be more flexible and return different response for success vs failure.

Example

@HttpGet
global static void getConvertedLead() {
    try{
        Id leadId = RestContext.request.params.get('leadId');
        Lead myLead = [SELECT Id FROM Lead WHERE Id = :leadId];
        //...convert lead
        RestContext.response.responseBody = Blob.valueOf(JSON.serialize(myLead));
    }catch(System.StringException e){
        RestContext.response.statusCode = 400;
        SalesforceError[] errs = new SalesforceError[]{ 
            new SalesforceError('BAD_REQUEST', 'Param: leadId is not a valid Id')
        };
        RestContext.response.responseBody = Blob.valueOf(JSON.serialize(errs));
    }catch(System.QueryException e){
        RestContext.response.statusCode = 404;
        SalesforceError[] errs = new SalesforceError[]{ 
            new SalesforceError('NOT_FOUND', 'Requested Lead not found')
        };
        RestContext.response.responseBody = Blob.valueOf(JSON.serialize(errs));
    }catch(Exception e){ //something else happened
        RestContext.response.statusCode = 500;
        SalesforceError[] errs = new SalesforceError[]{ 
            new SalesforceError('BAD_REQUEST', e.getMessage())
        };
        RestContext.response.responseBody = Blob.valueOf(JSON.serialize(errs));
    }
}

//standard salesforce error response structure
public class SalesforceError {
    public String errorCode;
    public String message;
    public SalesforceError(String errorCode, string message){
        this.errorCode = errorCode;
        this.message = message;
    }
}
  • 2
    +1, although a "not found" error would be a 404, not a 500. – sfdcfox Feb 22 '17 at 3:05
  • @sfdcfox good call. Updated – NSjonas Feb 22 '17 at 3:14
  • I don't know if it's a typo, or a new change in the recent sfdc release, but there is no body property in the RestResponse class. Only responseBody is available, and it's a blob. Could you kindly confirm @NSjonas? – SamuelDev Nov 20 '18 at 7:25
  • 1
    @SamuelDev you are corrected. answer updated – NSjonas Nov 20 '18 at 18:06
  • 1
    @RalphCallaway I feel like I have but I can't find any examples. I know the composite API does for sure, but the format is different all together. The reason I recommend following the format above is so that the error response is consistent with circumstances where the request doesn't even make it to your code. – NSjonas Aug 13 at 7:01

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.