Using the Datastore HTTP API

These days, your app needs to store and sync more than just files. With the Datastore API, structured data like contacts, to-do items, and game state can be synced effortlessly. Datastores support multiple platforms, offline access, and automatic conflict resolution.

Here are the basic concepts that underlie the Datastore API:

Datastores and tables
Datastores are containers for your app's data. Each datastore contains a set of tables, and each table is a collection of records. As you'd expect, the table allows you to query existing records or insert new ones.
Records

Records are how your app stores data. Each record consists of a set of fields, each with a name and a value. Values can be simple objects, like strings, integers, and booleans, or they can be lists of simple objects. A record has an ID and can have any number of fields.

Unlike in SQL, tables in datastores don't have a schema, so each record can have an arbitrary set of fields. While there's no requirement to have the same fields, it makes sense for all the records in a table to have roughly the same fields so you can query over them.

To follow along with this tutorial, you'll need to first create a "Dropbox API" app via the App Console.

Note: This tutorial uses the curl utility to make HTTP requests. This tool is available by default on OS X and Linux, but if it isn't available on your system, you can install it from http://curl.haxx.se/download.html.

Authentication

The Datastore API uses OAuth 2 for authentication. For the full details, see the Core API documentation. To complete OAuth 2 via raw HTTP, first visit the following URL (being sure to substitute in your app key):

https://www.dropbox.com/1/oauth2/authorize?client_id=<YOUR-APP-KEY>&response_type=code

In the browser, log in (if necessary), and click the "Allow" button to authorize your app. You will then be presented with an authorization code, which you can exchange for an access token. The access token is what you'll use to make authenticated calls to the Datastore API. If you're working with curl, the following command shows how to exchange the authorization code for an access token:

curl https://api.dropbox.com/1/oauth2/token -d grant_type=authorization_code -d code=<YOUR-AUTHORIZATION-CODE> -u <YOUR-APP-KEY>:<YOUR-APP-SECRET>

Here's an example HTTP request generated by the above command:

POST /1/oauth2/token HTTP/1.1
Authorization: Basic bmI4YWptcTM3ZjMzeHFsOmhkYmNubmZtOTE4cTVsMg==

code=8xRYXXRxYeQAAAAAAAAAAVbaNog5Q-GtJWJO7aOh4e4&grant_type=authorization_code

And here's an example response from the server:

HTTP/1.1 200 OK
Content-Type: text/javascript

{"access_token": "2KpF5HU1WC8AAAAAAAAAAXVIh5sWjCPQQ76ggWgUZX7CgP9QfJlC15RDC3X8LYc6", "token_type": "bearer", "uid": "178508400"}

Once you have an access token, you're ready to make calls to the Datastore API.

Creating a datastore

To create a named datastore, you can call /1/datastores/get_or_create_datastore. (The /1/ indicates the version of the Datastore API, which is currently always version 1.) Typically, the first (and possibly only) datastore you'll use is called "default." The following curl command will create a default datastore if it doesn't already exist and return the datastore's handle:

curl https://api.dropbox.com/1/datastores/get_or_create_datastore -d dsid=default -H "Authorization: Bearer <YOUR-ACCESS-TOKEN>"

Here's an example HTTP request:

POST /1/datastores/get_or_create_datastore HTTP/1.1
Authorization:  Bearer 2KpF5HU1WC8AAAAAAAAAAXVIh5sWjCPQQ76ggWgUZX7CgP9QfJlC15RDC3X8LYc6

dsid=default

And here's an example response from the server:

HTTP/1.1 200 OK
Content-Type: text/javascript

{"handle": "1PuUJ3DvMI71OYx1gcqWHzzdva2EpF", "rev": 0, "created": true}

Listing datastores

To see what datastores exist within an account, we can call /1/datastores/list_datastores, as in the following curl command:

curl https://api.dropbox.com/1/datastores/list_datastores -H "Authorization: Bearer <YOUR-ACCESS-TOKEN>"

Here's an example HTTP request:

GET /1/datastores/list_datastores HTTP/1.1
Authorization:  Bearer 2KpF5HU1WC8AAAAAAAAAAXVIh5sWjCPQQ76ggWgUZX7CgP9QfJlC15RDC3X8LYc6

And here's an example response from the server, in which we can see our newly created datastore:

HTTP/1.1 200 OK
Content-Type: text/javascript

{"datastores": [{"handle": "1PuUJ3DvMI71OYx1gcqWHzzdva2EpF", "rev": 0, "dsid": "default"}], "token": "cbd8804428bc888c7262b0193b43407033eb206b3e37bad2cc140591af3ec6f5"}

Retrieving a datastore snapshot

To retrieve a snapshot of the current contents of a datastore, we can use the /1/datastores/get_snapshot endpoint, as in the following curl command:

curl https://api.dropbox.com/1/datastores/get_snapshot?handle=<DATASTORE-HANDLE> -H "Authorization: Bearer <YOUR-ACCESS-TOKEN>

Here's an example HTTP request generated by the above command:

GET /1/datastores/get_snapshot?handle=1PuUJ3DvMI71OYx1gcqWHzzdva2EpF HTTP/1.1
Authorization:  Bearer 2KpF5HU1WC8AAAAAAAAAAXVIh5sWjCPQQ76ggWgUZX7CgP9QfJlC15RDC3X8LYc6

And here's an example response from the server, showing that our datastore is currently empty:

HTTP/1.1 200 OK
Content-Type: text/javascript

{"rows": [], "rev": 0}

Adding records

Our datastore is currently empty, but we can change that by submitting a delta to the server via the /1/datastores/put_delta endpoint. A delta is a list of changes to be applied to a datastore. The following curl command will submit a single change that inserts a record into a table called "tasks":

curl https://api.dropbox.com/1/datastores/put_delta -d handle=<DATASTORE-HANDLE> -d rev=0 -d changes="[[\"I\", \"tasks\", \"myrecord\", {\"taskname\": \"do laundry\", \"completed\": false}]]" -H "Authorization: Bearer <YOUR-ACCESS-TOKEN>"

Note that the changes parameter is a JSON list of changes. For the full grammar describing changes, see the Datastore HTTP API documentation. In our example, we have just a single change. Here's the same JSON, reformatted:

[
    [
        "I",
        "tasks",
        "myrecord",
        {
            "taskname": "do laundry",
            "completed": false
        }
    ]
]

Here's an example HTTP request generated by the above command:

POST /1/datastores/put_delta HTTP/1.1
Authorization:  Bearer 2KpF5HU1WC8AAAAAAAAAAXVIh5sWjCPQQ76ggWgUZX7CgP9QfJlC15RDC3X8LYc6

handle=1PuUJ3DvMI71OYx1gcqWHzzdva2EpF&rev=0&changes=%5B%5B%22I%22%2C+%22tasks%22%2C+%22myrecord%22%2C+%7B%22taskname%22%3A+%22do+laundry%22%2C+%22completed%22%3A+false%7D%5D%5D

And here's an example response from the server, confirming that our delta has been accepted and that the new datastore revision is revision 1:

HTTP/1.1 200 OK
Content-Type: text/javascript

{"rev": 1}

We can see the results of our delta by re-running the curl command above for get_snapshot:

GET /1/datastores/get_snapshot?handle=1PuUJ3DvMI71OYx1gcqWHzzdva2EpF HTTP/1.1
Authorization:  Bearer 2KpF5HU1WC8AAAAAAAAAAXVIh5sWjCPQQ76ggWgUZX7CgP9QfJlC15RDC3X8LYc6

Here's the response, with the returned JSON reformatted for clarity:

HTTP/1.1 200 OK
Content-Type: text/javascript

{
    "rows": [
        {
            "tid": "tasks",
            "data": {
                "taskname": "do laundry",
                "completed": false
            },
            "rowid": "myrecord"
        }
    ],
    "rev": 1
}

Tracking deltas from the server

So far, we've retrieved a full snapshot of the datastore each time we've wanted to retrieve updated content. It's generally more efficient to only retrieve deltas as they are applied to a datastore. The /1/datastores/get_deltas endpoint lets us fetch deltas that have been applied since a given revision of the datastore. The following curl command will give us all the deltas that have occurred since revision 0, when the datastore was first created:

curl https://api.dropbox.com/1/datastores/get_deltas?handle=1PuUJ3DvMI71OYx1gcqWHzzdva2EpF&rev=0 -H "Authorization: Bearer <YOUR-ACCESS-TOKEN>"

Here's an example HTTP request generated by the above command:

GET /1/datastores/get_deltas?handle=1PuUJ3DvMI71OYx1gcqWHzzdva2EpF&rev=0 HTTP/1.1
Authorization:  Bearer 2KpF5HU1WC8AAAAAAAAAAXVIh5sWjCPQQ76ggWgUZX7CgP9QfJlC15RDC3X8LYc6

And here's an example response from the server, showing the delta we uploaded when we added our first record:

HTTP/1.1 200 OK
Content-Type: text/javascript

{
    "deltas": [
        {
            "nonce": "",
            "changes": [
                ["I", "tasks", "myrecord", {"taskname": "do laundry", "completed": "false"}]
            ],
            "rev": 0
        }
    ]
}

Next steps

For the full details of the Datastore API, read the Datastore HTTP API documentation. For an example implementation of a Datastore API client, take a look at the Python SDK.