Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a custom APEX REST point /organization-contacts/* that accepts an array of queries to run. This is to try and find matching contacts (based on phone number in this example) in "batch". I realize I am limited by the 100 SOQL queries, but it's better to do this than 100 API calls.

I am new to Java and APEX, and although the code compiles, I am getting a "result":[{"message":" at [line:1, column:44]","errorCode":"JSON_PARSER_ERROR"}],"code":400 [...] error when I ping the endpoint with the following array of data, JSON encoded. My posting headers are correct.

What am I doing wrong in my APEX class that I can't even get to running searchBulk()? I am building the dynamic query (it may/may not contain additional WHERE parameters depending on the data) on my consumer side and passing the fully formed query to the endpoint.

The APEX Class:

global with sharing class ContactsSearchRestController {

   global class RequestBody {
       global List<sObject> contactstofind;

    global static List<sObject> searchBulk(ContactsSearchRestController.RequestBody req) {
        List<sObject> foundcontacts = new List<sObject>();

        for(sObject contacttofind : req.contactstofind) {
            List<sObject> foundcontact = Database.query(String.valueOf(contacttofind.get('contactquery')));
            //Loop over the found contacts and make sure we add our unique identifier to the results so that
            //our processor knows what searchcontact the results belong to
            for(sObject fc : foundcontact) {
                fc.put('externalid', contacttofind.get('externalid'));

        return foundcontacts;

The data being sent:

[contactstofind] => Array
        [0] => Array
                [contactquery] => SELECT Id FROM Contact WHERE Phone LIKE '%555%555%7781%' OR MobilePhone LIKE '%555%555%7781%' OR HomePhone LIKE '%555%555%7781%' OR OtherPhone LIKE '%555%555%7781%'
                [externalid] => 65202639238

        [1] => Array
                [contactquery] => SELECT Id FROM Contact WHERE Phone LIKE '%555%555%3993%' OR MobilePhone LIKE '%555%555%3993%' OR HomePhone LIKE '%555%555%3993%' OR OtherPhone LIKE '%555%555%3993%'
                [externalid] => 652054239

share|improve this question
I dont have time for a full answer here but here's a hint - ContactsSearchRestController.RequestBody req in your POST argument. SFDC will automatically deserialize the incoming POST body to the type ContactsSearchRestController.RequestBody and place it into variable req. Since it looks like you are sending an array, it won't deserialize into a list of sobjects – cropredy Aug 20 '14 at 19:00
@crop1645 Thanks for the answer - if I change req to anything but an sObject, I get a Initial term of field expression must be a concrete SObject: Object compile error for the Database.query() line. Any idea what I may be doing wrong with that? – Luke Shaheen Aug 20 '14 at 19:16
up vote 5 down vote accepted

You can design your own interface using simple Apex classes. So to allow this JSON to be posted:

    {"query": "SELECT ...", "externalId": "65202639238"},
    {"query": "SELECT ...", "externalId": "652054239"}

you just need a class with matching field names and to make the method signature accept an array of these classes:

global with sharing class ContactsSearchRestController {

    public class Item {
        public String query;
        public String externalId;

    global static List<SObject> searchBulk(Item[] items) {
        List<SObject> allSobs = new List<SObject>();
        for (Item i : items) {
            List<SObject> sobs = Database.query(i.query);
            for (SObject sob : sobs) {
                sob.put('externalid', i.externalId);
        return allSobs;

The platform will automatically deserialize the JSON and populate the items variable just as it will automatically serialize the List<SObject> return value.

share|improve this answer
Works perfectly. Thanks, the Typing is something I'm getting used to. This makes perfect sense. – Luke Shaheen Aug 20 '14 at 20:21
And, free bonus if you switch to XML. The platform will deserialize that, too. – sfdcfox Aug 20 '14 at 22:30
+1, but that inner class should also be global. Just had the following error: Result: [COMPILE FAILED]: (WS_Document) Argument type of global method must also be global: WS_Document.InnerHelperClass (Line: 5, Column: -1) – Novarg Apr 18 at 8:41

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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