[SalesForce] Passing custom model to Apex REST custom endpoint

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
            )

    )
)

Best Answer

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.

Related Topic