Handling REST Requests

At runtime, Mobile SDK creates a singleton instance of RestClient. You use this instance to obtain a RestRequest object and to send that object to the Salesforce server.

Although you can use RestRequest objects for many CRUD operations, let’s look at the most common use case: SOQL queries. Most other types of requests use the same flow with different input values. By default, SOQL query requests return up to 2,000 records per batch. In Mobile SDK 9.1 and later, you can specify a batchSize argument to customize the maximum batch size. This argument accepts any integer value between 200 and 2,000. Specifying a batch size does not guarantee that the returned batch is the requested size.

To create and send a SOQL REST request to the Salesforce server:

  1. To create a request object, call the RestClient factory method that takes a SOQL query.
    Swift
    1let request = 
    2    = RestClient.shared.request(forQuery: "SELECT Name FROM Contact LIMIT 10", apiVersion: SFRestDefaultAPIVersion, batchSize: 500)
    Objective-C
    1SFRestRequest *request = [[SFRestAPI sharedInstance]        
    2    requestForQuery:@"SELECT Name FROM Contact LIMIT 10"];
  2. Send your new REST request object using the REST client instance.
    Swift
    Option 1
    Use the RestClient shared Combine publisher. For example, using the following request:
    1let request = RestClient.shared.request(forQuery: "SELECT id, firstName, 
    2    lastName, phone, email, mailingStreet, mailingCity, mailingState, 
    3    mailingPostalCode FROM Contact WHERE AccountID = '\(acct.id)'", 
    4    apiVersion: nil, batchSize: 500)
    Pass the request to the RestClient.shared.publisher. In case you’ve never encountered call chaining, the following code comments describe what happens in a typical publisher sequence. This code is from the fetchContactsForAccount method of the Swift template app’s ContactsForAccountModel class.
    1// Use the RestClient publisher to send the request and return the raw REST response
    2contactsCancellable = RestClient.shared.publisher(for: request) 
    3    // Receive the raw REST response object
    4    .receive(on: RunLoop.main) 
    5
    6    // Try to convert the raw REST response to Data
    7    // Throw an error in the event of failure
    8    .tryMap({ (response) -> Data in  
    9        // Return the response as a Data byte buffer
    10        response.asData() 
    11    })
    12
    13    // Decode the Data object as JSON to produce an array 
    14    // of Contacts formatted as a ContactResponse object
    15    .decode(type: ContactResponse.self, decoder: JSONDecoder()) 
    16
    17    // Map the JSON array of Contacts
    18    .map({ (record) -> [Contact] in 
    19        // Copy the Contact array to the records 
    20        // member of ContactResponse
    21        record.records 
    22    })
    23
    24    // If tryMap failed, check for errors on the most recent 
    25    // object in the chain
    26    .catch( { error in
    27        Just([])
    28    })
    29
    30    // Store the array of contacts in the model’s published contacts
    31    // property for use by ContactsForAccountListView
    32    .assign(to: \.contacts, on:self)
    Contact and ContactResponse are structs that represent, respectively, a Contact record, and the formatted REST response to the SOQL query. Both objects are declared “Decodable”.
    1struct Contact :  Identifiable, Decodable  {
    2    let id: UUID = UUID()
    3    let Id: String
    4    let FirstName: String?
    5    let LastName: String?
    6    let PhoneNumber: String?
    7    let Email: String?
    8    let MailingStreet: String?
    9    let MailingCity: String?
    10    let MailingState: String?
    11    let MailingPostalCode: String?
    12}
    13
    14struct ContactResponse: Decodable {
    15    var totalSize: Int
    16    var done: Bool
    17    var records: [Contact]
    18}

    Do you see the beauty of using the RestClient publisher? You can send the request and handle the response in a single block of logic.

    Option 2
    Pass the request object to the send(request:_:) method. Typically, Swift apps handle the asynchronous response in the trailing closure, as shown here.
    1RestClient.shared.send(request: request) { [weak self] (result) in
    2    switch result {
    3        case .success(let response):
    4            self?.handleSuccess(response: response, request: request)
    5        case .failure(let error):
    6            SalesforceLogger.d(RootViewController.self, 
    7                message:"Error invoking: \(request) , \(error)")
    8    }
    9}
    In the following alternate example, the calling object implements the RestClientDelegate protocol to handle responses. It therefore calls the send(request:delegate:) overload and passes itself as the delegate.
    1// This class implements the RestClientDelegate protocol to handle responses
    2RestClient.shared.send(request, delegate: self)
    Objective-C
    Pass the request object to the send: parameter of the send:delegate: method. Typically in Objective-C apps, the calling object handles the asynchronous response in its own implementation of the SFRestDelegate protocol, as shown here.
    1// This class implements the SFRestDelegate protocol
    2[[SFRestAPI sharedInstance] send:request delegate:self];
    See Handling REST Responses.