Populating a Soup

To add Salesforce records to a soup for offline access, use the REST API in conjunction with SmartStore APIs.

When you register a soup, you create an empty named structure in memory that’s waiting for data. You typically initialize the soup with data from a Salesforce organization. To obtain the Salesforce data, you use Mobile SDK’s standard REST request mechanism. When a successful REST response arrives, you extract the data from the response object and then upsert it into your soup.

Hybrid Apps

Hybrid apps use SmartStore functions defined in the force.js library. In this example, the click handler for the Fetch Contacts button calls force.query() to send a simple SOQL query ("SELECT Name, Id FROM Contact") to Salesforce. This call designates onSuccessSfdcContacts(response) as the callback function that receives the REST response. The onSuccessSfdcContacts(response) function iterates through the returned records in response and populates UI controls with Salesforce values. Finally, it upserts all records from the response into the sample soup.

1force.query("SELECT Name,Id FROM Contact", 
2    onSuccessSfdcContacts, onErrorSfdc); var sfSmartstore = function() {
3    return cordova.require("com.salesforce.plugin.smartstore");};
4function onSuccessSfdcContacts(response) {
5    logToConsole()("onSuccessSfdcContacts: received " + 
6        response.totalSize + “ contacts");
7    var entries = [];
8    
9    response.records.forEach(function(contact, i) {
10           entries.push(contact);
11    });
12    
13    if (entries.length > 0) {
14        sfSmartstore().upsertSoupEntries(CONTACTS_SOUP_NAME,
15            entries,
16            function(items) {
17                var statusTxt = "upserted: " + items.length + 
18                    " contacts";
19                logToConsole()(statusTxt);
20            }, 
21         onErrorUpsert);
22    }
23}
24
25function onErrorSfdc(param) {
26    logToConsole()("onErrorSfdc: " + param);
27}function onErrorUpsert(param) {
28    logToConsole()("onErrorUpsert: " + param);
29}

iOS Native Apps

iOS native apps use the SFRestAPI protocol for REST API interaction. The following code creates and sends a REST request for the SOQL query SELECT Name, Id, OwnerId FROM Account. If the request is successful, Salesforce sends the REST response to the requestForQuery:send:delegate: delegate method. The response is parsed, and each returned record is upserted into the SmartStore soup.
1- (void)requestAccounts
2{
3    SFRestRequest *request = [[SFRestAPI sharedInstance] 
4        requestForQuery:@"SELECT Name, Id, OwnerId FROM Account"];
5    [[SFRestAPI sharedInstance] send:request delegate:self];
6}
7
8//SFRestAPI protocol for successful response
9- (void)request:(SFRestRequest *)request didLoadResponse:(id)dataResponse
10{
11    NSArray *records = dataResponse[@"records"];
12    if (nil != records) {
13        for (int i = 0; i < records.count; i++) {
14            [self.store upsertEntries:@[records[i]] 
15                               toSoup:kAccountSoupName];
16        }
17    }
18}

Android Native Apps

For REST API interaction, Android native apps typically use the RestClient.sendAsync() method with an anonymous inline definition of the AsyncRequestCallback interface. The following code creates and sends a REST request for the SOQL query SELECT Name, Id, OwnerId FROM Account. If the request is successful, Salesforce sends the REST response to the provided AsyncRequestCallback.onSuccess() callback method. The response is parsed, and each returned record is upserted into the SmartStore soup.
1private void sendRequest(String soql, final String obj) 
2throws UnsupportedEncodingException {
3    final RestRequest restRequest = 
4        RestRequest.getRequestForQuery(
5            getString(R.string.api_version), 
6            "SELECT Name, Id, OwnerId FROM Account", "Account");
7    client.sendAsync(restRequest, new AsyncRequestCallback() {
8        @Override
9        public void onSuccess(RestRequest request, 
10            RestResponse result) {
11            // Consume before going back to main thread
12            // Not required if you don't do main (UI) thread tasks here
13            result.consumeQuietly();
14            runOnUiThread(new Runnable() {
15                @Override
16                public void run() {            
17                    // Network component doesn’t report app layer status.
18                    // Use the Mobile SDK RestResponse.isSuccess() method to check  
19                    // whether the REST request itself succeeded.
20                    if (result.isSuccess()) {
21                        try {
22                            final JSONArray records = 
23                                result.asJSONObject().getJSONArray("records");
24                            insertAccounts(records);
25                        } catch (Exception e) {
26                            onError(e);
27                        } finally {
28                            Toast.makeText(MainActivity.this, 
29                                "Records ready for offline access.",
30                                Toast.LENGTH_SHORT).show();
31                        }
32                    }
33                }
34            });   
35        }
36        
37        @Override
38        public void onError(Exception e) {
39            // You might want to log the error 
40            // or show it to the user
41        }
42    });
43}	
44
45/**
46 * Inserts accounts into the accounts soup.
47 *
48 * @param accounts Accounts.
49 */
50public void insertAccounts(JSONArray accounts) {
51    try {
52        if (accounts != null) {
53            for (int i = 0; i < accounts.length(); i++) {
54                if (accounts[i] != null) {
55                    try {
56                        smartStore.upsert(
57                            ACCOUNTS_SOUP, accounts[i]);
58                    } catch (JSONException exc) {
59                        Log.e(TAG, 
60                            "Error occurred while attempting "
61                            + "to insert account. Please verify "
62                            + "validity of JSON data set.");
63                    }
64                }
65            }
66        }
67    } catch (JSONException e) {
68        Log.e(TAG, "Error occurred while attempting to "
69            + "insert accounts. Please verify validity "
70            + "of JSON data set.");
71    }
72}