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, follow these steps:

1. Call the RestClient factory method 

RestClient takes a SOQL query. It creates a request object.

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.

1Task {
2    do {
3        let response = try await RestClient.shared.send(request: request)
4        self?.handleSuccess(response: response, request: request)
5    } catch let error as RestClientError {
6        SalesforceLogger.d(
7            RootViewController.self,
8            message: "Error invoking: \(request), \(error)"
9        )
10    } catch {
11        SalesforceLogger.d(
12            RootViewController.self,
13            message: "Unexpected error invoking: \(request),
14            \(error.localizedDescription)"
15        )
16    }
17}

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.

We've Moved

Welcome to the new home of the Mobile SDK Developer Guide! For now, the Japanese guide can be found in PDF form.