Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

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:

@RestResource(urlMapping='/organization-contacts/*')
global with sharing class ContactsSearchRestController {

   global class RequestBody {
       global List<sObject> contactstofind;
   }

@HttpPost   
    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'));
                foundcontacts.add(fc);
            }                
        }

        return foundcontacts;
    }
}

The data being sent:

Array
(
[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 –  crop1645 Aug 20 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? –  John Aug 20 at 19:16

1 Answer 1

up vote 4 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:

@RestResource(urlMapping='/organization-contacts/*')
global with sharing class ContactsSearchRestController {

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

    @HttpPost   
    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);
            }
            allSobs.addAll(sobs);
        }
        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. –  John Aug 20 at 20:21
    
And, free bonus if you switch to XML. The platform will deserialize that, too. –  sfdcfox Aug 20 at 22:30

Your Answer

 
discard

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.