14 Storage

Oracle Mobile Cloud Service (MCS) provides a Storage API for storing media in the cloud. As a mobile app developer, you can use this API in your mobile app to store and retrieve objects, such as files, text, images, and JSON objects.

What is the Storage API?

The Storage API enables your mobile app to store, update, retrieve, and delete media, such as JSON objects, text files, and images, in collections in your MCS environment. Storage is key based, and you can use roles to restrict access to a collection. You can also grant anonymous access to shared collections to anyone who also has backend access by adding the collection name to the Security_CollectionsAnonymousAccess environment policy.

Note that this API isn’t intended to act as a database-as-a-service (DBaaS) solution by storing business data used by external systems, nor is it intended to host HTML 5 applications as a content management system (CMS) would.

How Mobile Applications Access Collections

Mobile applications access collections through the Storage API. As a mobile developer, you can access this API through the mobile client SDK, or directly through REST calls. As a service developer, you can call the Storage API from the code that you write to implement a custom API.

To access the Storage API through the mobile client SDK, you use a backend manager class.

Here is an example of using the backend manager class in an Android app to access a collection.

try {
    Storage storage = 
        MobileBackendManager.getManager().getDefaultMobileBackend(this).getServiceProxy(Storage.class);
    StorageCollection imagesCollection = 
        storage.getStorageCollection("FIF_Images");
    StorageObject imageToUpload = 
        new StorageObject(null, imageBytes, "image/jpeg");
    StorageObject uploadedImage = imagesCollection.post(imageToUpload);
    } catch(ServiceProxyException e) {int errorCode = e.getErrorCode();
            ...
}
To call a Storage endpoint from custom code, you invoke the custom code SDK method that calls the appropriate Storage API operation, as shown in the following example:
// Get metadata about the objects in the attachments collection.
// List most recently modified first.
service.get('/mobile/custom/incidentreport/attachments',
  function (req, res) {
    req.oracleMobile.storage.getAll('attachments', 
    {orderBy: 'modifiedOn:desc', sync: true}).then(
      function (result) {
        res.send(result.statusCode, result.result);
      },
      function (error) {
        res.send(error.statusCode, error.error);
      }
    );
  }); 
For more information on how custom code can retrieve collection information and store and retrieve objects, see Accessing the Storage API from Custom Code.

Shared and User Isolated Collections

A collection is either shared or user isolated.

When a collection is shared, no one owns the collection or an object, and the objects are kept in a shared space. Those with certain mobile user roles, permissions, and access to the backend, or anonymous access to the backend associated with the collection, can update an object. Note that in both shared and user isolated collections, each object has an ID that is unique to the collection.

When a collection is user isolated, users who have Read-Only (All Users) access can read objects in other users’ spaces. Users with Read-Write (All Users) access can both read and write objects in other users’ spaces. Anonymous access is not permitted in user isolated collections.

Let's look at some examples of this behavior using the following scenarios:

Shared Collection

An online magazine is leveraging the Storage API as a way for authors to submit, change, or read, articles. They’ve provisioned a shared collection called articles, as shown in the figure below.
  • Ben has contributed articles on bugs and bats, while Art has written about cows and dogs.

  • The dogs article is shared, allowing both Ben and Art to collaborate on it.

  • Art and Ben are able to modify any article regardless of who originally submitted it.

  • Dee can read all the articles, but she can't make changes.

However, if this shared collection is added to the Security_CollectionsAnonymousAccess environment policy, then Ben, Art, Dee or anyone who has access to the backend can submit, change, or read articles.

User Isolated Collection

An online magazine has provisioned a user isolated collection called Articles, as shown in the following figure.

  • Ben and Art can read and edit their articles, and upload new articles as well. They can’t read or write each other's files.

  • Dee can read only her article. Because her role is InactiveAuthor, which gives her Read-Only permission, she can't upload any new articles.

  • Eva, the editor, can make changes to any file and return it to the author's isolated space.

  • Raj, the publisher, can view all the articles, but he can't make changes.

  • Because users are isolated, the authors don't have to worry about naming conflicts with others. Objects in different isolation spaces can have the same name (as is the case for the “dogs” articles by Dee and Art).

  • Eva and Raj can access Ben, Art, and Dee’s objects only by specifying a user qualification parameter. When Eva wants to make changes to Art’s article, the call that enables her to write to Art’s user space must include Art’s ID.

Anonymous users don’t have access to user isolated collections. If a user isolated collection is added to the Security_CollectionsAnonymousAccess environment policy, it’s just ignored.

Permissions in Shared and User Isolated Collections

You can designate who can access and update objects in a collection by attaching access permissions to mobile user roles, or for anonymous access, by adding the shared collection name to the Security_CollectionsAnonymousAccess environment policy.

For example, to include the Articles collection use Security_CollectionsAnonymousAccess=Articles.

If the collection does not, or cannot permit anonymous access:

  • Art and Ben’s Author mobile user role is associated with the Read-Write permission.

    • In the shared collection, they can read and update any article within the shared collection.

    • In the user isolated collection, they can read and update their own articles.

  • In contrast, Dee has the InactiveAuthor mobile user role, which gives her Read-Only permission.

    • In the shared collection, Dee can read Art’s article about dogs, as well as various articles from either Art or Ben about bugs, cows, and bats. Unlike Ben or Art, she can’t delete articles or add new ones.

    • In the user isolated collection, she can read her own article about dogs, but she can’t read Art’s article about dogs.

  • For user isolated collections, mobile user roles that are associated with the Read-Only (All Users) permission can view any object. The Read-Write (All Users) permission allows users to view and update objects in other users’ spaces. Because her role as Editor has a Read-Write (All Users) permission, Eva can read and edit various authors’ files, such as those authored by Ben and Art.

Note:

Although different mobile user roles can grant access to the same objects in a collection, such as Eva (Editor), Ben (Author), and Art (also Author), in the user isolated collection, the objects remain in their respective isolated spaces.

When anonymous access is allowed on a shared collection, access and the ability to update an object is granted to any authenticated user as well, regardless of role. This means adding a collection name to the Security_CollectionsAnonymousAccess environment policy overrides permissions given through roles. Take care when allowing anonymous access to a collection. Security is more limited than with role-based permissions.

Working with Collections

Mobile apps can use only the collections that are associated with a mobile backend.

You can add existing collections to a mobile backend. You can also create new collections as part of the process of creating a mobile backend. There’s a page for each approach:

  • The Storage page that you access by clicking This is an image of the sidebar menu. > Applications > Storage can be used to create collections and view a master list of all collections. To associate one of the collections with a mobile backend, select the collection, click More, and then select Associate Mobile Backends.

  • The Storage page that you access from the Storage tab on a mobile backend page lets you associate a collection with the mobile backend as well as create a new collection that is associated with that mobile backend.

Using the Storage Configuration Pages

You can use the Storage pages to perform tasks such as create and configure a collection, configure whether the collection is shared or user isolated, and associate a collection with a mobile backend.

To open the Storage page for all collections, click This is an image of the sidebar menu. to open the side menu. Next, click Applications and then click Storage.

Using this page, you can create collections, edit existing ones, associate them with mobile backends, and publish them. To find out more about collections, policies, and other artifacts, see Lifecycle.

You can find out when the collections listed were created or updated and which mobile backends are using them by first selecting a collection and then expanding Used By and History.

To associate a collection with a mobile backend, select the collection, click More, and then select Associate Mobile Backends.

To create or update collections for a specific mobile backend, click This is an image of the sidebar menu. to open the side menu. Next, click Applications and then Mobile Backends.

To find out if a mobile backend has collections assigned to it, click Storage on the mobile backend page.

In addition to the tasks described here, you can also do the following tasks:

Task Description

Set Permissions

Configure who can access the collection and how. See Adding Access Permissions to a Collection.

Maintain Locally Stored Objects

Set how long before the data stored locally on the device becomes stale and needs to be refreshed. See Offline Data Storage.

Test

Test the endpoint operations that manage collections and their objects. See Testing Runtime Operations Using the Endpoints Page.

Deploy

Deploy collections. See Collection Lifecycle.

Creating Collections

The following tasks enable you to create and update collections:

  1. Defining a Collection
  2. Adding Access Permissions to a Collection
  3. Updating the Collection
  4. Adding Objects to a Collection
Defining a Collection

The New Collection dialog lets you name a collection so that it can be identified in REST calls and designate it as shared or user isolated.

  1. Open the Storage page either from a mobile backend or by clicking Storage in the side menu, and click New Collection.

  2. Complete the New Collection dialog:

    1. Enter a name for your collection. This name is used to form the Universal Resource Identifier (URI) for the collection. Within the context of the API call, the collection name is referred to as the collection ID:
      {baseUri}/mobile/platform/storage/collections/{collection ID}
      For example, for a collection named FiF_UploadedImages (cloud storage of images uploaded from mobile apps), the URI call would look like this:
      {baseUri}/mobile/platform/storage/collections/FiF_UploadedImages

      For a closer look at Storage API syntax, see Storage API Endpoints.

    2. Choose the collection type: Shared or User Isolated. You can’t change the scope of the collection after you’ve set it. For details and examples, see Shared and User Isolated Collections.

    3. If needed, enter a short description for the purpose of the collection, to be displayed in the list of collections.

  3. Click Create.

Note:

When you initially create a collection, it’s in a draft state, in version 1.0.
  • You can modify the collection name, access permissions, and its contents. Remember, you can’t change the collection type after it’s created.

  • You can version a collection. You might want to increment a collection’s major and minor version numbers when you publish it or when you add new objects.

  • While in the draft state, a collection can be moved to the trash from the More menu.

Collection Metadata

In addition to the basic properties like size (in bytes), and description, the collection metadata includes the collection name that identifies it for REST calls.

When you create a collection, the Storage API defines it using the following metadata:
Property Value Type Description

description

string

The short description. This is an optional value.

id

string

The collection name, which is used in the uniform resource identifier (URI). For example:

{baseURI}/mobile/platform/storage/collections/{collection}

The collection name is case-sensitive, meaning that mycollection and Mycollection are two different collections.

Adding Access Permissions to a Collection

Collection access is granted through an anonymous user setting in the environment policy file, or managed by mobile user roles. Once a mobile user role is defined, you can also grant which roles can read and write objects in the collection. To see what mobile user roles are available, go to the Mobile User Management UI and click Roles. To learn more about roles and mobile users, see Creating and Managing Mobile User Roles and Creating Mobile Users and Assigning Roles.

Anonymous Access to Collections

Anonymous access is often given to users who just want to check information on an app without logging in or needing an assigned role. Weather apps, where a user can check their local weather, are a good example of this.

Likewise, you can grant anonymous access to your shared collection. Once a shared collection is created, the administrator adds its name to the Security_CollectionsAnonymousAccess policy. You can then read and write objects to the shared collection via the REST API or the SDKs using anonymous access. To read and write objects to the shared collection from the UI, grant Read-Writepermission to any role on the collection’s properties page. For environment policies, see Environment Policies and Their Values.

Keep in mind that when you add a shared collection to the policy, both anonymous and named users have access and read/write privileges to the collection.

Note:

If you try to upload an object to a shared collection which allows anonymous access, an error dialog appears. To work around this issue, in the Properties page, specify any mobile user role for the collection’s Read-Write permission type.

Role-Based Access to Collections

To define which mobile user roles can read and write objects in a collection:
  1. In the Storage page, select a collection and then click Open.
  2. In the Properties page, specify one or more mobile user roles for each permission type.
    • Read-Only and Read-Write access apply to all collections (shared or user isolated).

    • You can specify Read-Only (All Users) and Read-Write (All Users) permissions only if the collection type is user-isolated.

    Permission Shared User Isolated

    Read-Only

    Read-only access to all of the objects in a collection. For example, both a field technician and a customer can read promotional material like coupons, but they can’t update them.

    Read-only access to a user isolated collection. When the Read-Only permission is applied to user isolated collections, for example, a customer can view images (like a coupon), but he can’t update them, or submit additional ones (only a user with Read-Write (All Users) privileges can add an object to the customer’s user space). Because this is a user isolated collection, the customer can view only his images (or other customer-specific objects that are intended only for him). The Read-Only permission also prevents him from adding additional work orders or deleting them.

    Read-Write

    A user can override any object in the collection.

    A user can override the objects in his isolated space. For example, a customer can update the images of broken appliances that he’s submitted. Because this is a user isolated collection, the images that he can add (and update) are intended only for him. Because these images exist in his isolated space, he can update these objects, but no one else’s. Likewise, he can add or delete images, but can’t do this in anyone else’s isolated space.

    Read-Only (All Users)

    NA

    A user can read objects in all spaces. For example, a field technician can see the images updated by any customer, but she can’t update them, delete them, or add new ones.

    Read-Write (All Users)

    NA

    A user can override objects in all spaces. If a field technician has Read-Write (All Users) permission, then she can update work orders submitted by any customer.

    Note:

    By default, mobile users can’t access a collection until they’ve been assigned mobile user roles that are associated with the Read-Write, Read-Only, Read-Write (All Users) or Read-Only (All Users) permissions. Anonymous users can’t access a shared collection until the collection has been added to the Security_CollectionsAnonymousAccess environment policy. Anonymous users are automatically granted Read-Write permissions.
Updating the Collection

You can update the name, description and access to a collection. You can’t however, change the collection type.

  1. On the Storage page, select a collection and then click Open.
  2. Click Properties. (The Properties page opens by default when you first create a collection. On subsequent visits, the Content page opens by default.)
  3. Change the name, description or access as needed.
  4. Click Save.
Offline Data Storage

The client SDK’s Sync Client library, in conjunction with the Storage library, enables mobile apps to cache a collection’s objects for offline use and performance improvement. The apps can then use the cached objects instead of re-retrieving them from Storage, as described in How Synchronization Works with the Storage APIs. If a collection’s content changes infrequently, then consider enabling those mobile apps to cache the collection’s objects by selecting Enable the mobile client SDK to cache collection data locally for offline use.

When Enable the mobile client SDK to cache collection data locally for offline use is selected, the objects that a mobile app retrieves can remain in the cache for the period set in the Sync_CollectionTimeToLive policy. This value is conveyed to the app through the Oracle-Mobile-Sync-Expires response header. By default, the timeout period is set for 24 hours (86,400 seconds).

To learn how to configure the timeout period, see Environment Policies.

Don’t select this option for time-critical data, where a cached value might be misleading. For example, if the collection contains current stock prices, you shouldn’t select this option, because users expect the latest value (or no value at all).

If your mobile app isn’t using the client SDK’s Storage library, and your app is caching Storage objects, then you can take advantage of the following request and response headers:

Type Header Description
Request Oracle-Mobile-Sync-Agent When this header is set to true in the request, then the response includes either Oracle-Mobile-Sync-Expires or Oracle-Mobile-Sync-No-Store.
Response Oracle-Mobile-Sync-Expires Specifies when the returned resource must be marked as expired. Uses RFC 1123 format, for example EEE, dd MMM yyyyy HH:mm:ss z for SimpleDateFormat. This value is determined by the Sync_CollectionTimeToLive policy.
Response Oracle-Mobile-Sync-No-Store When set to true, the client mustn’t cache the returned resource.

To learn more about data caching, see Data Offline and Sync.

Adding Objects to a Collection

You can populate a collection with objects.

These steps show how to add an object using the UI. When you add an object from the UI, the ID is generated automatically. If you want to assign a specific ID to an object, use the Storage API, the custom code SDK, or the client SDK for your mobile platform. For details, see Storing an Object.
  1. On the Storage page, select a collection and click Open.
    • If this collection has no objects, click Upload Files and then browse to and retrieve the object. Click Open.
    • If this collection already has objects, click Upload in the Content page. Browse to and retrieve the object. Click Open.
  2. If the collection is shared, click Add. If you have the identity domain administrator role, you can also upload to user isolated collections. Add the user realm and user name to the User Name Required dialog, and click Ok. You can only select from users whose roles have been granted permission to the collection. (Assign these roles in the Properties page.)
  3. To view the object data, select it from the list.

Tip:

To permanently remove an object from a collection, select it and click Delete.
Object Metadata

When you upload an object, the Content page displays basic metadata, such as size, content type, version information, and who uploaded it. Using this page, you can also delete unneeded objects, or filter them. Some functions in user isolated collections are only available if you have the identity domain administrator role.

Property Value Type Description/Usage

ID

string

The object name, which is used for operations on a single object. It is the last value specified in the URI.

Content Length

integer

The size, in bytes.

Content Type

media type

The media type for the data, such as image/jpeg for a JPEG image, or application/json for JSON.

ETag

string (an integer in quotes, for example, "17")

A value that represents the version of the object. It's used with the If-Match and If-None-Match HTTP request headers.

Created By

user name

The name of the user who uploaded the data.

Created On

time stamp (In ISO 8601)

The time that the object was most recently stored on the server. Time stamps are stored in UTC.

Modify By

user name

The name of the user who modified the object.

Modified On

time stamp (in ISO 8601)

The time when the server received a request for an object. Time stamps are stored in UTC.

User ID

string

For a user isolated collection, the ID of the user whose space the object is in.

Managing Collections

You can update collections in terms of their contents, but you can’t change the type of the collection. That is, if the collection is a user isolated collection, you can’t change it to a shared collection.

Associating a Collection with a Backend

Associating a collection makes its contents available to a specific backend. The associated collection is a dependency.

  1. In the Storage page, select a collection.

  2. Click More and then select Associate Mobile Backends.

  3. In the Associate Backends dialog, select one or more backends from the list.

    The surrounding text describes this image.
  4. Click Add.

In the details pane, you can see any associated backends by expanding Used By.

You can also associate a collection with a backend this way:

  1. Open the backend.

  2. Click the Storage tab and then choose Select Collections.

  3. Choose one or more collections from the Select Collections dialog, and then click Select.

Removing a Collection from a Backend

You might want to disassociate a collection from a backend so that you can change the backend's state without affecting the collection. Or you might want to disassociate the collection and associate a different one.

  1. In the Storage page, select a collection.

  2. In the Details section on the right, view the Used By list.

  3. To delete the association, click the X that follows the backend version number.

  4. You’ll be prompted to remove the dependency. Click Remove.

To remove a collection from a backend:

  1. Open the backend.

  2. Open the Storage page.

  3. Click the X adjacent to the collection that you want to remove.

  4. In the Confirm Remove Dependency dialog, click Remove.

Calling the Storage API from Your App

To access the Storage API from your app code, you can use the SDK for your platform.

For info on setting up the SDKs, see Connecting Your Application to a Mobile Backend. For complete reference documentation of the SDKs, see Oracle Mobile Cloud Service Help Center.

Here are some code snippets that you can use in your apps once you have your SDK set up.

iOS

The code to retrieve an object might look like this:

- (void) downloadData{
    
    //fill in IDs for collection and object
    NSString* collection_Id = @"";
    NSString* object_Id = @"";

    // Get storage object
    AppDelegate* appDelegate = [[UIApplication sharedApplication] delegate];
    OMCMobileBackend* mbe = [appDelegate myMobileBackend];
    OMCStorage* storage = [mbe storage];
    
    // Get your collection
    OMCStorageCollection* aCollection = [storage getCollection:collection_Id];
    
    // Get your object from your collection
    OMCStorageObject* aObject = [aCollection get:object_Id];
    
    // Get the data from payload of your object
    NSData* data = [aObject getPayloadData];
    
    lblDownloadStatus.text = @"Download finished";

}

Here’s code you can use to add an object:

- (void) uploadData{
 
    //Specify a text object to be added to a collection called "myCollection"
    NSString* collection_Id = @"myCollection";
    NSString* payload = @"This is a simple text object";
    NSString* contentType = @"text/plain";

    if ( payload == nil || [payload isEqualToString:@""]) {
        
        lblUploadStatus.text = @"There is nothing to upload";
    }
    else{
        
        // Get storage object
        AppDelegate* appDelegate = [[UIApplication sharedApplication] delegate];
        OMCMobileBackend* mbe = [appDelegate myMobileBackend];
        OMCStorage* storage = [mbe storage];
        
        // Get collection where you want to upload new data
        OMCStorageCollection* aCollection = [storage getCollection:collection_Id];
        
        // Create new data from payload
        NSData* payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
        OMCStorageObject* aObject = [[OMCStorageObject alloc] setPayloadFromData:payloadData
                                                                 withContentType:contentType];
        
        // Post data to collection
        [aCollection post:aObject];
        
        lblUploadStatus.text = @"Upload finished";
    }
}

Android

The code to retrieve an object might look like this:

private Storage mStorage;
private String collectionID = "YOUR_COLLECTION_ID";
private String objectID = "YOUR_OBJECT_ID";

...

try {
    //Initialize and obtain the storage client
    mStorage = MobileBackendManager.getManager().getDefaultMobileBackend(this).getServiceProxy(Storage.class);
    //Fetch the collection
    StorageCollection collection = mStorage.getStorageCollection(collectionID);
    //Fetch the object
    StorageObject object = collection.get(objectID);
    //Get the payload
    InputStream payload = object.getPayloadStream();
    //Display the image
    ImageView imageView = (ImageView) findViewById(R.id.imageView);
    imageView.setImageBitmap(BitmapFactory.decodeStream(payload));

} catch (ServiceProxyException e) {
    e.printStackTrace();
}

Here’s code you can use to add an object:

private Storage mStorage;
private String collectionID = "YOUR_COLLECTION_ID";
private String mPayload = "YOUR_PAYLOAD";
private String mContentType = "YOUR_CONTENT_TYPE";

...
//Create or upload an object with specified ID, payload and content-Type
private void uploadObject(String id, String payload, String contentType){
    try {
        //Initialize and obtain the storage client
        mStorage = MobileBackendManager.getManager().getDefaultMobileBackend(this).getServiceProxy(Storage.class);
        //Fetch the collection
        StorageCollection collection = mStorage.getStorageCollection(collectionID);
        //Create an object with id, payload and content-Type explicitly specified
        StorageObject object = new StorageObject(null, payload.getBytes(), contentType);
        //Upload the object
        collection.post(object);
    } catch (ServiceProxyException e) {
        e.printStackTrace();
    }
}

Cordova and JS

Here’s code to retrieve an object:

function downloadData(){
			varcollectiondId = 'COLLECTION_ID';
			var objectId = 'OBJECT_ID';

      mcs
        .mobileBackend
        .storage
        .getCollection(collectionId, null)
        .then(getCollectionSuccess)
        .then(getObjectSuccess)
        .catch(error);

      function getCollectionSuccess(storageCollection){returnstorageCollection.getObject(objectId, 'json');
      }

      function getObjectSuccess(storageObject){
        console.log(storageObject.name);
      }

      function error(error){
        console.log(error.statusCode);
      }
    }

    function uploadData(){
			varcollectiondId = 'COLLECTION_ID';
			varobjectId = 'OBJECT_ID';
			varfileName = 'YOUR_FILE_NAME';
			varpayload = 'YOUR_PAYLOAD';
			var contentType = 'text/plain';

      mcs
        .mobileBackend
        .storage
        .getCollection(collectionId, null)
        .then(getCollectionSuccess)
        .then(getObjectSuccess)
        .catch(error);

      function getCollectionSuccess(storageCollection){var storageObject = newmcs.StorageObject(collection);
        storageObject.setDisplayName(fileName);
        storageObject.loadPayload(payload, contentType);return storageCollection.postObject(storageObject);
      }

      function postObjectSuccess(response){
        console.log(response.storageObject.id);
      }

      function error(error){
        console.log(error.statusCode);
      }
    }

Testing Runtime Operations Using the Endpoints Page

You can test client REST calls for collections manually through a command line tool or utility, from a mobile app running on a device or simulator, or you can use the Endpoints page to test various operations.

Using the Endpoints page for the Storage API, you can try out basic collection calls, which would typically be exercised by a mobile app. These endpoints would be called directly by calling REST APIs, indirectly (by calling the client SDK), or through custom code. Instead of configuring a device or simulator, or entering the command manually, you can test the API by first entering mobile app user credentials and parameters appropriate to the call and then by clicking Test Endpoint. The page displays the payload and the status code.

You can access the Endpoints page by clicking Storage in Platform APIs section that is located at the bottom of the APIs page for a mobile backend. You can also open the page by clicking Storage in the Platform APIs section at the bottom of the APIs page. (You open this page by clicking This is an image of the hamburger icon that opens the sidebar menu. The menu items are Home, Applications, Analytics, and Administration. Under the Applications heading, Mobile Backends is selected. to open the side menu. You then click Applications> Mobile Backends and then APIs).

Storage API Endpoints

The Storage API has endpoints for retrieving, paginating, and ordering collections and also for retrieving, updating, and removing objects.

Here, we give a brief overview of the Storage API endpoints. For detailed information, see REST APIs for Oracle Mobile Cloud Service.

Getting a Single Collection

To get the metadata about a collection, such as ID, description, and whether it is user isolated, call the GET operation on the {collection} endpoint as follows:

GET {baseUri}/mobile/platform/storage/collections/{collection}
For example, for a collection named images:
GET {baseUri}/mobile/platform/storage/collections/images

Getting All Collections Associated with a Mobile Backend

To get a list of the collections that are associated with a mobile backend, call the GET operation on the collections endpoint as follows:

GET {baseUri}/mobile/platform/storage/collections

Storing an Object

The Storage API has two operations for creating objects. The operation that you use depends on if you want to specify the object’s ID or you want the ID to be generated automatically.

When you create an object using your own ID, remember that, for shared collections, the ID must be unique to the collection. For user isolated collections, the ID must be unique to the user’s space.

Always include the Content-Type header to specify the media type of the object being stored. This property also specifies the media type to return when the object is requested. If you don’t include this header, then the content type defaults to application/octet-stream.

Note that Storage doesn’t transform or encode an object. Storage stores the exact bytes that you send in the request. For example, you can’t send a Base-64 encoded image and store it as a binary image by including a Content-Type header set to image/jpeg and a Content-Encoding header set to base64. You can use a custom API to perform the transformation for you, as shown in the code examples in storage.store(collectionId, object, options, httpOptions).

Specifying the Object Identifier

When performing a PUT operation, the identifier of the object corresponds to the last value specified in the URI. For example, to store an object with an ID called part1524:

PUT {baseUri}/mobile/platform/storage/collections/images/objects/part1524
Creating an Object (If One Doesn't Already Exist)
Put the wildcard (*) character in the request's If-None-Match header to force the PUT operation to create the object with the specified object ID only if no other object exists with that ID. Specifying the wildcard causes the call to fail if another object already exists with the same ID. For example:
PUT {baseUri}/mobile/platform/storage/collections/images/objects/part1542

Headers:
  If-None-Match: *
Generating an Object Identifier
To generate the identifier for an object and then store the object, use the POST operation. Unlike the PUT operation, there’s no identifier specified at the end of the URI for a POST operation. For example:
POST {baseUri}/mobile/platform/storage/collections/images/objects

The URI that accesses the newly created object is returned through the Location header in the response, and the ID attribute is included in the response body.

What Happens When an Object is Created?

When an object is created:

  • The content is stored.

  • The value of the Content-Type field in the request is stored. (This becomes the Content-Type field definition returned when the object is requested using a GET operation.)

  • An entity tag (ETag) value is assigned.

  • The createdBy value is set to the user ID of the user who performed the create operation.

  • The createdOn value is set to the time the object was stored on the server.

Updating an Object

Objects are updated using the PUT operation. For the PUT call, specify the same identifier that was specified or generated when the object was created. Because objects are opaque, updating an object completely replaces the previous contents.

What Happens When an Object Is Updated?

When a PUT is performed on an object, the following occurs:

  • The content is completely replaced.

  • The value of the ETag changes.

  • The modifiedBy value is set to the user ID for whom the mobile app performed the PUT operation.

  • The modifiedOn value is set to the time the object was stored on the server.

Optimistic Locking

Optimistic locking is a strategy to use when you want to update an object only if object was not updated by someone else after you originally retrieved it. To implement this strategy, do one of the following:

  • Put the timestamp of when you last retrieved the object in the If-Unmodified-Since header.

  • Put the object’s ETag in the If-None-Match header.

For example, if the ETag value from the previous call is 2, then the PUT operation in the following example is performed only when the If-None-Match value of "2" matches the ETag of the object (part1524). If the versions don’t match, then the call’s PUT operation isn’t performed and part1524 remains unchanged.
PUT{baseUri}/mobile/platform/storage/collections/images/objects/part1524

Headers:
  If-None-Match: \"2\"
You can get a similar result using If-Unmodified-Since:
PUT {baseUri}/mobile/platform/storage/collections/images/objects/part1524

Headers:
  If-Unmodified-Since: Mon,30 Jun 2014 19:43:31 GMT     

Retrieving Objects

You can get a list of the objects in a collection, and you can get an object.

Retrieving a List of Objects

To get the metadata about a set of objects in a collection, use the GET operation on the /collections/{collection}/objects endpoint. This metadata includes the object’s ID, its name, and size. The metadata also includes the canonical link and self links. For a full list of properties, see Taking a Look at Object Metadata.

In this example, images is the name of a shared collection.
GET {baseURI}/mobile/platform/storage/collections/images/objects

If the collection is user isolated and you have READ_ALL or READ_WRITE_ALL access, then you must include the user query parameter and specify which user's objects you want listed, even if you want to see your own objects (use * to list all user’s objects). Note that you provide the user’s ID, not the user name. For example:

GET {baseURI}/mobile/platform/storage/collections/images/objects?user=0cea04ee-9e26-4de3-ad6b-00a66c8d3b96
Paging Through a List of Objects

If you don’t want to see all the results, or if you want to get the results in small blocks, use the limit and offset query parameters to request a subset of items.

Use the limit parameter to restrict the number of items returned. The default is 100. Define offset as the zero-based starting point for the returned items. The returned JSON body contains links for retrieving both the next and previous sets of items.

The following example gets the metadata for 50 objects, starting with the 201st object.
Get {baseUri}/mobile/platform/storage/collections/images/objects?offset=200&limit=50
Ordering
Use the orderBy parameter to control the order of the returned items. You can specify which property to order on and specify whether to put the items in ascending (asc) or descending (desc) order:
Get {baseUri}/mobile/platform/storage/collections/images/objects?orderBy=contentLength:desc
You can sort by the name, modifiedBy, modifiedOn, createdBy, createdOn, or contentLength property.

Note:

You can order by one property only (either asc or desc).
Querying
Use the q query parameter to restrict the list of returned objects to the value specified for the id, name, createdBy, or modifiedBy attributes.
Get {baseUri}/mobile/platform/storage/collections/images/objects?q=part
The objects returned are based on a case-sensitive, partial match of the id, name, createdBy, and modifiedBy attributes. With this example, the results might include an item with an ID of part1524 and an item modified by bonapart.
Retrieving an Object

Use the GET operation to retrieve the entire object. When performing the GET operation, the identifier (such as part1524 in the following example) is specified at the end of the URI.

Storage always returns the exact bytes that were stored. If the Accepts header doesn’t match the Content-Type that the object was stored with, then it returns a 406 status code.

In this example, the object is returned only if the Etag does not match. You can use this strategy prevent re-fetching an object if it hasn’t changed.
Get {baseUri}/mobile/platform/storage/collections/images/objects/part1524

Headers:
  If-None-Match: \"2\"

Deleting an Object

To remove an object from a collection, call the DELETE operation. Deleting an object is permanent. There’s no way to restore an object after you call this operation.
DELETE {baseUri}/mobile/platform/storage/collections/images/objects/part1524
To safely remove an object, use the If-None-Match header with the object’s ETag, or the If-Unmodified-Since header with the timestamp of when you last retrieved the object:
DELETE {baseUri}/mobile/platform/storage/collections/images/objects/part1524

Headers:
  If-None-Match: \"2\"

As described in Updating an Object, you can use these headers to prevent overriding a change that another user made after you originally retrieved the object.

Optimizing Performance

You can use these strategies to optimize performance when you retrieve an object:

Check If Exists

To check if an object exists, use the HEAD operation instead of a GET operation. The HEAD operation returns the same information except for the actual object value.

Put If Absent

You can use the If-None-Match header with a wildcard (*) value in a PUT operation to store an object only when (or if) it isn’t already included in the collection.

When you use this strategy, the call executes only when the ETag is absent, which is true only if the object does not exist.
PUT {baseUri}/mobile/platform/storage/collections/profiles/objects/uprofile

Headers:
  If-None-Match: *

In this example, if the uprofile object doesn’t have an ETag, then myProfile.txt is stored as the uprofile object.

Get If Newer

If you have already retrieved an object, and you want to re-fetch it only if it has changed, use the GET operation with the If-None-Match or If-Modified-Since header to retrieve the object only if there has been a change since the last time the object was fetched.

  • If-None-Match

    This example re-fetches the object only if the ETag is not 2.

    GET {baseUri}/mobile/platform/storage/collections/images/objects/part1542
    
    Headers:
      If-None-Match: \"2\"
  • If-Modified-Since

    This example re-fetches the object only if it was modified after the date and time specified. Otherwise, the response status is 304 not modified.

    GET {baseUri}/mobile/platform/storage/collections/images/objects/part1542
    
    Headers: 
      If-Modified-Since: Mon, 30 Jun 2014 19:43:31 GMT
Reading Part of an Object (Chunking Data)

If the mobile app needs to get a large object like a video file, you can use the Range header to retrieve a subset of the object. This field lets the mobile app retrieve the data in chunks, rather than all at once, by requesting a subset of bytes. Using this strategy, you can start streaming a video, or start displaying the contents of a long list before you fetch the whole object.

Here are examples of byte-range specifier values:

  • First 100 bytes: bytes=0-99

  • Second 100 bytes: bytes=100-199

  • Last 100 bytes: bytes=-100

  • First 100 and last 100 bytes: bytes=0-99,-100

This example gets the first 100 and last 100 bytes of a profile to display a preview of the object’s contents:

GET {baseUri}mobile/platform/storage/collections/profiles/objects/uprofile

Headers:
  Range: bytes=0-99,-100