Apex · Integration · REST

Combining RESTful Web Services and Site.com for creating publicly asccessible URL

The Force.com REST API lets you use a simple and lightweight API to access Force.com data, using standard OAuth, together with a choice of data flavors – XML and JSON. The REST API is configured out of the box to suit the basic CRUD (create, read, update and delete) operations of data management.

Apex REST augments this functionality and makes it possible for developers to create your own REST-based web services using Apex. It has all of the advantages of the REST architecture, provides the ability to define custom logic and includes automatic argument/object mapping. However, in general one needs to authenticate the endpoint for accessing the content.

This article provides is to give you a demonstration of combining RESTful webservices and Site.com to provide an URL which can be publicly accessed without need of any Authentication. For anyone who wants to expose their public data using a simple URL, this would be helpful.

Example: Assigning Case By Location

Let’s assume a company has agents in the field that will be submitting cases back to their Force.com application. It’s a small to medium sized company, but large enough that they have one team out on the road creating the case and then specific employees responsible for handling the cases by region.

For simplicity’s sake, we’ll have the support team assigned to areas by state – but the road warriors of the company may be anywhere in the country when they submit the case back to the company.

To make this example sufficiently complex that it couldn’t be simply solved by workflow rules – let us also assume that the first action in any support case is to email out an attachment that must always be the most recent in the support team’s library to the customer.

So the logic would need to work in the following manner:

  1. Determine the current customer and their email.
  2. Create a support case and assign it to the support person responsible for the state that the customer is based.
  3. Find the attachment associated with the most recent Support Library object associated to the type of case being submitted.
  4. Email the customer with the attachment and notify them that their case has been entered into the system.

Solving this without Apex REST would be a multistep process. If the customer data wasn’t stored on the mobile device somewhere, the application would need to hit the query end point to make sure they have the correct information. It would also need to find the correct support person before hitting the create endpoint. It would need to probably rely on a trigger to correctly handle if not 3, certainly 4. While acceptable, this process might take longer, be hard to maintain and may not provide the field agent with the response information they need right away.

Or the developer could create a single Apex REST endpoint. The code would look something like this:


@RestResource(urlMapping='/FieldCase/*')

global with sharing class RESTCaseController {

@HttpPost

global static String createNewCase(String companyName, String caseType) {

System.debug('COMPANY: '+companyName);

System.debug('CASE TYPE: '+caseType);

List<Account> company = [Select ID, Name, Email__c, BillingState from Account where Name = :companyName];

List<Support_Member__c> support;

if(company.size() > 0) {

support = [SELECT ID, User__c, Name, User__r.Email from Support_Member__c WHERE Support_State__c = :company[0].BillingState LIMIT 1];

}

List<Support_Documentation__c> doc = [SELECT ID from Support_Documentation__c WHERE Type__c = :caseType ORDER BY CreatedDate ASC LIMIT 1];

if(company.size() == 0 || support.size() == 0 || doc.size() == 0) {

return 'No support data exists for this problem';

}

Case c = new Case();

c.OwnerId = support[0].User__c;

c.AccountId = company[0].Id;

c.Subject = caseType + ' for '+companyName;

c.Status = 'Open';     insert c;

sendEmail(companyName, company[0].Email__c, doc[0].Id, support[0].Name, support[0].User__r.Email);

return 'Submitted case to '+support[0].Name+' for '+companyName+'. Confirmation sent to '+company[0].Email__c;

}

}

With a second “sendEmail” function, which would handle getting the correct attachment and then send that out to the customer. Some of this might be, depending on the use case, be better handled by a trigger or workflow still – but this example shows you can simplify a more complicated business process down to a single endpoint and not have to code a multiple step procedure which will perform slower and be more difficult to maintain. Apex developers don’t need to use a different structure to set their code up for use with an Apex REST endpoint with the exception of the @HttpPost (or related HTTP method) annotation. By utilizing this custom class, you can automate several tasks within Apex itself simplified down to a single endpoint.

Setting up an Apex REST endpoint

To declare a class as a custom endpoint, you only need to annotate a global class with “@RestResource” and define the name of the endpoint.

In the above example, we start the class with the following lines:

@RestResource(urlMapping=’/FieldCase/*’) global with sharing class RESTCaseController {

This will define “FieldCase” as an accessible endpoint and the full URI would be constructed from your instance URL concatenated with “/services/apexrest/FieldCase”. For example, something like “https://na8.salesforce.com/services/apexrest/FieldCase”.

What happens at that endpoint is completely up to the developer depending on how the class is defined. REST defines endpoints as a combination of URI and HTTP methods, the class can declare different actions depending on if the incoming request is an HTTP GET, POST, PUT or DELETE request. After this class is saved, Apex REST sets everything else up: there are no additional steps required from the developer to make the endpoint available, or trigger data decoding or anything else – the custom REST endpoint is ready to go.

Utilizing the REST Request and REST Response objects

Any Apex REST service that we define can accept a REST Request and Response objects as the first parameters if necessary. These objects will provide the developer with additional information about the REST transaction that is taking place and give them control over processing that information before the transaction is complete. If this information is not needed, as in our POST example above, the objects can be left out of the method definition.

Combining the REST Class and Site.com

In my example below the purpose is to expose all the ‘Special Event’ object records as JSON so that the client can use that information and display those events in their website.

For this purpose I need Site.com Enabled with the Site.com Profile having access to the ‘Special Event’object.

Example of Utilizing GET Request:


@RestResource(urlMapping='/calEventsLinvio')

global class calEventsLinvioRestService {

@HttpGet

global static void doGetCalEvents() {

RestContext.response.addHeader('Content-Type', 'Application/JSON');

String name = RestContext.request.params.get('name');

//- //DO NOT include any events that have expired.//-//

//-//Include ONLY events that have a "Status" of "Published" and a checkmark next to "Include in Calendar" and starting later than today with Status of ‘Published’ and with ‘Include in calendar’checkbox checked.//-//

list<evt__Special_Event__c > calEvnts = new list<evt__Special_Event__c >();

//Record types - Conference,Quick Event,Seminar,Specialty Event, Web Meeting

list<evt__Special_Event__c > LstQuickEvnts= [select name, evt__City__c, evt__Country__c, evt__Short_Description__c, Registration_URL__c, Quick_Event_URL__c , evt__Event_Type__c, evt__Start__c, Location__c  from evt__Special_Event__c WHERE evt__Start__c >=LAST_N_DAYS:0 AND evt__Status__c='Published' AND evt__Include_in_Calendar__c = True AND RecordType.name='Quick Event'];

list<evt__Special_Event__c > LstConferenceEvnts= [select name, evt__City__c, evt__Country__c, evt__Short_Description__c, Registration_URL__c, Conference_Site_URL__c , evt__Event_Type__c, evt__Start__c, Location__c  from evt__Special_Event__c WHERE evt__Start__c >=LAST_N_DAYS:0 AND evt__Status__c='Published' AND evt__Include_in_Calendar__c = True AND RecordType.name='Conference'];

list<evt__Special_Event__c > LstSeminarEvnts= [select name, evt__City__c, evt__Country__c, evt__Short_Description__c, Registration_URL__c, Seminar_Event_URL__c, evt__Event_Type__c, evt__Start__c, Location__c  from evt__Special_Event__c WHERE evt__Start__c >=LAST_N_DAYS:0 AND evt__Status__c='Published' AND evt__Include_in_Calendar__c = True AND RecordType.name='Seminar'];

list<evt__Special_Event__c > LstSpecialityEvnts= [select name, evt__City__c, evt__Country__c, evt__Short_Description__c, Registration_URL__c, evt__Event_Landing_Page__c, evt__Event_Type__c, evt__Start__c, Location__c  from evt__Special_Event__c WHERE evt__Start__c >=LAST_N_DAYS:0 AND evt__Status__c='Published' AND evt__Include_in_Calendar__c = True AND RecordType.name='Specialty Event'];

list<evt__Special_Event__c > LstWebMeetingEvnts= [select name, evt__City__c, evt__Country__c, evt__Short_Description__c, Registration_URL__c, Web_Meeting_Event_URL__c, evt__Event_Type__c, evt__Start__c, Location__c  from evt__Special_Event__c WHERE evt__Start__c >=LAST_N_DAYS:0 AND evt__Status__c='Published' AND evt__Include_in_Calendar__c = True AND RecordType.name='Web Meeting'];

for(evt__Special_Event__c QuickEvent: LstQuickEvnts){

calEvnts.add(QuickEvent);

}

for(evt__Special_Event__c ConferenceEvent: LstConferenceEvnts){

calEvnts.add(ConferenceEvent);

}

for(evt__Special_Event__c SeminarEvent: LstSeminarEvnts){

calEvnts.add(SeminarEvent);

}

for(evt__Special_Event__c SpecialityEvent: LstSpecialityEvnts){

calEvnts.add(SpecialityEvent);

}

for(evt__Special_Event__c WebMeetingEvent: LstWebMeetingEvnts){

calEvnts.add(WebMeetingEvent);

}

String EventsJSON = JSON.serialize(calEvnts);

RestContext.response.responseBody = Blob.valueof(EventsJSON);

}

}

Now by utilizing my Site.com URL-  and appending services/apexrest/URLMapping to the Site.com URL . We will have our desired Public Endpoint which exposes required Special Event Records without need of any Authentication.

Summary

By utilizing custom Apex REST endpoints, developers can tailor the REST API to suit the business needs of their application. An endpoint can be defined with an Apex Class using the @RestResource annotation, and the method annotations allow the endpoint to behave specifically for creating, updating, deleting and querying data within the instance. In areas where the REST API has already proven successful, i.e. third party web integrations and mobile applications – the ability to use Apex REST will make those applications even more versatile and powerful.

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s