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 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.
The unit of sharing is a single datastore, and one or more datastores may be shared between accounts. Any datastore with a shareable ID can be shared by assigning roles to principals, creating an access control list. Any Dropbox account with the correct permissions will then be able to open the shared datastore by ID.
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.
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.
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}
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"}
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}
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 }
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 } ] }
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.