Monday, August 6, 2018

How to expose salesforce apex class as rest api

Salesforce Developer Apex Rest Exposing Apex
// Salesforce - Developer - REST - Expose Your Apex Class as a Web Service:

You can expose your Apex class methods as a REST or SOAP web service operation.
By making your methods callable through the web, you allow third party
applications (or your own external applications) to access your data.

Apex REST methods can be used in managed and unmanaged packages. When calling
Apex REST methods that are contained in a managed package, you need to include
the managed package namespace in the REST call URL. For example, if the class
is contained in a managed package namespace called packageNamespace and the
Apex REST methods use a URL mapping of /MyMethod/*, the URL used via REST to
call these methods would be of the form

Instead of using custom Apex code for REST and SOAP services, external
applications can integrate with Salesforce by using Salesforce’s REST and SOAP
APIs. These APIs let you create, update, and delete records. However, the
advantage of using Apex web services is that Apex methods can encapsulate
complex logic. This logic is hidden from the consuming application. Also, the
Apex class operations can be faster than making individual API calls, because
fewer roundtrips are performed between the client and the Salesforce servers.
With an Apex web service call, there is only one request sent, and all
operations within the method are performed on the server.

The security context under which Apex web service methods run differs from the
security context of Salesforce APIs. Unlike Salesforce APIs, Apex web service
methods run with system privileges and don’t respect the user’s object and field
permissions. However, Apex web service methods enforce sharing rules when
declared with the with sharing keyword.

All sObjects, standard or custom, come with a REST API, so we do not have to
create a REST API for each of our objects.  Apex REST is used for defining
custom interactions.  Apex REST is good for abstracting complex interactions
to a single call:

1. Inserting / updating multiple objects
2. Callouts to external systems
3. Custom search interfaces.

All custom Apex REST services are accessed in the same namespace.  For example,
https://na15.salesforce.com/services/apexrest/<custom_path> where <custom_path>
can be something like v1/joborders

Making your Apex class available as a REST web service is straightforward:

1. Define your class as global

2. Add the @RestResource annotation to the class

   @RestResource(urlMapping='/Account/*')
   global with sharing class MyRestResource {
       @HttpGet
       global static Account getRecord() {
           // Add your code
       }
   }

   As you can see, the class is annotated with
   @RestResource(urlMapping='/Account/*). The base endpoint for Apex REST is
   appended to the base endpoint to form the endpoint for your REST service.
   For example, in the class example, the REST endpoint is

   The URL mapping is case-sensitive and can contain a wildcard character (*).

   We should think about versioning your API endpoints so that you can provide
   upgrades in functionality without breaking existing code. You could create t
   wo classes specifying URL mappings of /Cases/v1/* and /Cases/v2/* to
   implement this functionality.

3. Define methods as global static

4. Add annotations to the class and methods.

   @HttpGet: Reads or retrieves records (HTTP VERB: GET)
   @HttpPost: Create records (HTTP VERB: POST)
   @HttpDelete: Deletes records (HTTP VERB: DELETE)
   @HttpPut: Update existing records or create records. (HTTP VERB: PUT)
   @HttpPatch: Update (HTTP VERB: PATCH)

@RestResource(urlMapping='/Cases/*')
global with sharing class CaseManager {

    @HttpGet
    global static Case getCaseById() {
        RestRequest request = RestContext.request;
        // grab the caseId from the end of the URL
        String caseId = request.requestURI.substring(
          request.requestURI.lastIndexOf('/')+1);
        Case result =  [SELECT CaseNumber,Subject,Status,Origin,Priority
                        FROM Case
                        WHERE Id = :caseId];
        return result;
    }

    @HttpPost
    global static ID createCase(String subject, String status,
        String origin, String priority) {
        Case thisCase = new Case(
            Subject=subject,
            Status=status,
            Origin=origin,
            Priority=priority);
        insert thisCase;
        return thisCase.Id;
    }  

    @HttpDelete
    global static void deleteCase() {
        RestRequest request = RestContext.request;
        String caseId = request.requestURI.substring(
            request.requestURI.lastIndexOf('/')+1);
        Case thisCase = [SELECT Id FROM Case WHERE Id = :caseId];
        delete thisCase;
    }    

    @HttpPut
    global static ID upsertCase(String subject, String status,
        String origin, String priority, String id) {
        Case thisCase = new Case(
                Id=id,
                Subject=subject,
                Status=status,
                Origin=origin,
                Priority=priority);
        // Match case by Id, if present.
        // Otherwise, create new case.
        upsert thisCase;
        // Return the case ID.
        return thisCase.Id;
    }

    @HttpPatch
    global static ID updateCaseFields() {
        RestRequest request = RestContext.request;
        String caseId = request.requestURI.substring(
            request.requestURI.lastIndexOf('/')+1);
        Case thisCase = [SELECT Id FROM Case WHERE Id = :caseId];
        // Deserialize the JSON string into name-value pairs
        Map<String, Object> params = (Map<String, Object>)JSON.deserializeUntyped(request.requestbody.tostring());
        // Iterate through each parameter field and value
        for(String fieldName : params.keySet()) {
            // Set the field and value on the Case sObject
            thisCase.put(fieldName, params.get(fieldName));
        }
        update thisCase;
        return thisCase.Id;
    }   

}

// Salesforce - Developer - REST - Expose Your Apex Class as a Web Service - Testing:

Testing your Apex REST class is similar to testing any other Apex class.  Just
call the class methods by passing in parameter values and then verify the
results. For methods that don’t take parameters or that rely on information in
the REST request, create a test REST request.

In general, here’s how you test Apex REST services. To simulate a REST request,
create a RestRequest in the test method, and then set properties on the request
as follows. You can also add params that you “pass” in the request to simulate
URI parameters.

// Set up a test request
RestRequest request = new RestRequest();

// Set request properties
request.requestUri =
    + recordId;
request.httpMethod = 'GET';

// Set other properties, such as parameters
request.params.put('status', 'Working');

// more awesome code here....
// Finally, assign the request to RestContext if used
RestContext.request = request;

If the method you’re testing accesses request values through RestContext, assign
the request to RestContext to populate it (RestContext.request = request;).

1. In the Developer Console, select File | New | Apex Class.

2. For the class name, enter CaseManagerTest and then click OK.

3. Replace the autogenerated code with the following class definition.

@IsTest
private class CaseManagerTest {

    @isTest static void testGetCaseById() {
        Id recordId = createTestRecord();
        // Set up a test request
        RestRequest request = new RestRequest();
        request.requestUri =
            + recordId;
        request.httpMethod = 'GET';
        RestContext.request = request;
        // Call the method to test
        Case thisCase = CaseManager.getCaseById();
        // Verify results
        System.assert(thisCase != null);
        System.assertEquals('Test record', thisCase.Subject);
    }

    @isTest static void testCreateCase() {
        // Call the method to test
        ID thisCaseId = CaseManager.createCase(
            'Ferocious chipmunk', 'New', 'Phone', 'Low');
        // Verify results
        System.assert(thisCaseId != null);
        Case thisCase = [SELECT Id,Subject FROM Case WHERE Id=:thisCaseId];
        System.assert(thisCase != null);
        System.assertEquals(thisCase.Subject, 'Ferocious chipmunk');
    }

    @isTest static void testDeleteCase() {
        Id recordId = createTestRecord();
        // Set up a test request
        RestRequest request = new RestRequest();
        request.requestUri =
            + recordId;
        request.httpMethod = 'GET';
        RestContext.request = request;
        // Call the method to test
        CaseManager.deleteCase();
        // Verify record is deleted
        List<Case> cases = [SELECT Id FROM Case WHERE Id=:recordId];
        System.assert(cases.size() == 0);
    }

    @isTest static void testUpsertCase() {
        // 1. Insert new record
        ID case1Id = CaseManager.upsertCase(
                'Ferocious chipmunk', 'New', 'Phone', 'Low', null);
        // Verify new record was created
        System.assert(Case1Id != null);
        Case case1 = [SELECT Id,Subject FROM Case WHERE Id=:case1Id];
        System.assert(case1 != null);
        System.assertEquals(case1.Subject, 'Ferocious chipmunk');
        // 2. Update status of existing record to Working
        ID case2Id = CaseManager.upsertCase(
                'Ferocious chipmunk', 'Working', 'Phone', 'Low', case1Id);
        // Verify record was updated
        System.assertEquals(case1Id, case2Id);
        Case case2 = [SELECT Id,Status FROM Case WHERE Id=:case2Id];
        System.assert(case2 != null);
        System.assertEquals(case2.Status, 'Working');
    }   

    @isTest static void testUpdateCaseFields() {
        Id recordId = createTestRecord();
        RestRequest request = new RestRequest();
        request.requestUri =
            + recordId;
        request.httpMethod = 'PATCH';
        request.addHeader('Content-Type', 'application/json');
        request.requestBody = Blob.valueOf('{"status": "Working"}');
        RestContext.request = request;
        // Update status of existing record to Working
        ID thisCaseId = CaseManager.updateCaseFields();
        // Verify record was updated
        System.assert(thisCaseId != null);
        Case thisCase = [SELECT Id,Status FROM Case WHERE Id=:thisCaseId];
        System.assert(thisCase != null);
        System.assertEquals(thisCase.Status, 'Working');
    } 

    // Helper method
    static Id createTestRecord() {
        // Create test record
        Case caseTest = new Case(
            Subject='Test record',
            Status='New',
            Origin='Phone',
            Priority='Medium');
        insert caseTest;
        return caseTest.Id;
    }         

}

4. Press CTRL+S to save.


5. Run all the tests in your org by selecting Test | Run All.