Oh my god. It's full of code!

Salesforce REST API musings

So this post is going to be more questions, thoughts, and things to check on more than any useful data. Salesforce Apex REST services is currently in pilot, meaning you can get it enabled for your organization. What it does is allows you to take an Apex class and turn it into a RESTful…. thingy. So you tell your class what URL to be responsible for, put in methods that handle the various HTTP verbs (GET, POST, PUT, DELETE). Now each of these verbs essentially maps to a different CRUD operation (create = post, read = get, update = put, delete = delete). Of course you can also pass in query params by using the ? and & symbols. Now then, it seems to me, that the easiest design at least to get started would be to create 4 very generic methods and have them figure out what they are supposed to do by looking at the URL structure and query params.

Say for example you created your Apex class and told it to listen for anything in the /myservice/ sub folder. You’d mark your apex class like this

RestResource(urlMapping=’/myservice/*’)

now to access it, you’d simple go to

https://%5Byourinstance%5D.salesforce.com/services/apexrest/myservice

If you were to visit that page in your browser (ignoring the authentication error you’d get) you’d hit the method marked with @HttpGet because your browser by default sends GET requests. Following me so far? Now say you wanted to write a rest class that would work with accounts and contacts. Now first you’d say, ok I’ll need at least 8 methods then (4 methods per object X 2 objects). But wait, really you’ll more or less be recreating the same methods for both. Sure the functionality might change a bit based on the object type and optional query data, but not so dramatic as to require completely separate methods. For basic CRUD operations it feels like maybe you could make your methods generic enough to cover all sObjects.

Right now you might be like ‘uhh what the hell are you talking about?’ but here, I’ll try and give an example. Straight from the developer blog over at Salesforce they have a sample that looks like this

@HttpGet
global static Case getCaseRecord(RestRequest req, RestResponse res) 
{
    String caseNum = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
    Case c = CustomCaseMgmt.getCase(caseNum);
    return c;
}

Makes enough sense right? You make a get request you get a case back. But what if I don’t want a case, what if I want a contact. You need another method for that (which leads me to the question how does the REST api know which one to call in a situation, can there even be multiple? AHHH MY BRAIN!). Anywho of course my novice programmer brain says ‘wait, lets just make a nice abstract method that will work for any sObject!’. So I end up with something like

@HttpGet
global static list<sObject> getRecord(RestRequest req, RestResponse res)
{
    //No idea if this is the right way to get url arguments. Seems clunky and wrong but its from the sample code
    string objectType = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
    string objectId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+2);
    
    string queryString = 'select name, id from ' + objectType + ' where id = \''+objectId+'\''; 
    list<sObject> objects = Database.query(queryString);
    
    return objects;    
}

See, now I have no idea if this is a good idea or not. You call the URL and in the arguments you tell it the type of object you want, and the ID of the object as well. Later I would certainly build on this to allow the user to specify a limit, offset, and what fields they want, and maybe even allow them to write custom where statements if they were familiar with SOQL. Point being, I can save myself writing multiple methods if I have 1 method that changes it’s behavior based on the data in the URL query string. Writing very dynamic methods might be a bit harder up front, but think of the re-usability! Also you get off writing a lot less test code, which is always a win in my book. Hell if I/you did this right we could have a downloadable class that pretty much instantly enables any org total REST functionality for all their objects!

So ideally you’d be able to do something like

https://%5Byourinstance%5D.salesforce.com/services/apexrest/myservice/contact/003000000000000

and if that was a get request it would hit the get method, see that you and that you want the contact with id of 003000000000000. Of course you would be able to replace contact with any sObject and it should still work. Then you could maybe make your method cooler and make the Id an optional parameter and let developers just enter a query in your url like

https://%5Byourinstance%5D.salesforce.com/services/apexrest/myservice/contact/?query=lastname like ‘jones%’ and createdDate > LAST_YEAR&limit=50

To only find people names jones who where created this year. Doing something like that would make your API super powerful but still fairly intuitive for developers who are used to working with the force.com platform. Of if you didn’t want to support full SOQL queries you could have some keywords like

https://%5Byourinstance%5D.salesforce.com/services/apexrest/myservice/contact/?lastname=jones&createdDate=THIS_YEAR&limit=50

but of course that is less flexible and requires more coding in your method to handle the special keywords, and tends to remove the ability to do LIKE, greater than, less than, not equal to, etc (unless you build in some more crazyness). Anyway, you see where I am going with this?

Of course it only gets harder when you start dealing with creates and updates (theoretically deletes should be just as easy, but some syntax issues might make it hard, I dunno). So I have no idea if I should continue down this road of attempting to create generic REST methods or not. I’d really like to start walking this path putting my best foot forward, but I’m not sure what that is. This is the part where the intelligent developer community comes out and tells me I’m a total n00b and how to do it right (and it turns out its some insanely complicated horrific mess that seems easy to them but makes me want to cry. That would be my luck).

Anyway, take this all with a grain of salt. I just learned about the REST API last week, and while I’m starting to write code, it doesn’t even work in my dev org yet. So hell if I know. I feel like I’m stumbling in the dark here but I know where I want to be. If you have any insight on this approach, feel free to leave comments or whatever.

6 responses

  1. Anonymous

    What you’re using here is not the Force.com REST API, but APEX REST services. It seems to me you would get all of the functionality you want with the REST API (http://wiki.developerforce.com/index.php/Getting_Started_with_the_Force.com_REST_API).

    You would use the REST services to write custom transactions that don’t exist in the REST API. If you’re doing simple object lookups and updates, then API will be fine, and you won’t need to write custom code.

    July 8, 2011 at 4:39 pm

  2. You know, I knew about the REST API but never really put two and two together. I feel like a total idiot now. Thank you for kind of helping me make that connection and clearing up a lot of confusion. Sigh, maybe one day I’ll stop being an idiot XD

    July 8, 2011 at 5:39 pm

  3. Charan

    I am trying this code..

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

    global class rest
    {
    @HttpGet
    global static List getOpenCases(RestRequest req, RestResponse res) {
    String companyName = req.params.get(‘companyName’);
    Account company = [ Select ID, Name, Email__c, BillingState from Account where Name = :companyName];

    List cases = [SELECT Id, Subject, Status, OwnerId, Owner.Name from Case WHERE AccountId =: company.Id];
    return cases;

    }

    }
    provided in http://www.wiki.developerforce.com

    I saved it and when I am trying to access this through

    https://ap1.salesforce.com/services/apexrest/FieldCase?companyName=GenePoint

    I am getting Invalid Session ID error (XML response).

    Can you please help me out in sorting this.

    Regards,

    Charan

    July 26, 2011 at 6:02 am

    • You can’t just straight up all a rest resource like that. You have to include a session ID in the header of the request. For example in coldfusion it would look like

      October 11, 2012 at 4:05 pm

  4. Hello, Neat post. There’s an issue together with your website in web explorer, could check this? IE still is the market leader and a large element of other people will omit your excellent writing due to this problem.

    March 30, 2013 at 10:21 am

  5. Anonymous

    apex
    rest
    api

    May 21, 2015 at 1:06 pm

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