Tutorial: REST API

REST API

Prerequisites

  • Create an account on [[service]]
  • Create an application (or namespace), in this documentation we will use the test-rest application
  • Have the curl command available (or another tool to build HTTP requests)

Look at the following sample, which makes it possible to browse data level per level: https://io.datasync.orange.com/samples/tree/

Write Data

WARNING: Security concerns are explained later in this document!

Writing data is as easy as sending a PUT request:

$ curl -X PUT -H 'content-type: application/json' "https://io.datasync.orange.com/base/<application>/<path>.json" -d '<JSON data>'

Command example:

$ curl -X PUT -H 'content-type: application/json' "https://io.datasync.orange.com/base/test-rest/main/sub/infos.json" -d '{"id": 22, "version": 42, "detail": "this is a test", "level2": {"level21": "22", "level22": true}}'

Server response:

{"id":22,"version":42,"detail":"this is a test","level2":{"level21":"22","level22":true}}

After sending the request, you should see the data in the data tab of the [[console]]. Notice that the main / sub / infos levels have been created automaticaly. Be careful, some characters are forbidden in level keys (. $ [ ] # / see doc). Similarly, no more than 32 levels are authorized in the database. The server returns written data in the HTTP response.

In order to store data in table form, use the HTTP POST method instead of PUT. It makes the [[service]] server create a new level in your tree. The key of the created level is unique and temporally ordered. In this case, the server returns the ID of the created level in the HTTP response.

Command example:

$ curl -X POST -H 'content-type: application/json' "https://io.datasync.orange.com/base/test-rest/history/main/sub.json" -d '{"id": 22, "version": 42, "detail": "this is a test", "level2": {"level21": "22", "level22": true}}'

Server response:

{"name":"-KolzsgbVnMc4s7lr-c-"}

Read Data

To retrieve data, a simple GET is needed:

$ curl –X GET https://io.datasync.orange.com/base/<application>/<path>.json

Command example:

$ curl -X GET "https://io.datasync.orange.com/base/test-rest/main/sub/infos.json"

Server response:

{"id":22,"version":42,"detail":"this is a test","level2":{"level21":"22","level22":true}}

Command example, applying to a sub level:

$ curl -X GET "https://io.datasync.orange.com/base/test-rest/main/sub/infos/level2.json"

Server response:

{"level21":"22","level22":true}

Command example, applying to the whole database:

$ curl -X GET "https://io.datasync.orange.com/base/test-rest.json

Server response:

{"main":{"sub":{"infos":{"id":22,"version":42,"detail":"this  is a  test","level2":{"level21":"22","level22":true}}}},"history":{"main":{"sub":{"-KolzsgbVnMc4s7lr-c-":{"id":22,"version":42,"detail":"this  is a test","level2":{"level21":"22","level22":true}}}}}}

Server can format data in a pretty way, using the print=pretty option:

Command example, requesting the whole database in a pretty format:

$ curl -X GET "https://io.datasync.orange.com/base/test-rest.json?print=pretty"

Server response:

{
  "main": {
    "sub": {
      "infos": {
        "id": 22,
        "version": 42,
        "detail": "this is a test",
        "level2": {
          "level21": "22",
          "level22": true
        }
      }
    }
  },
  "history": {
    "main": {
      "sub": {
        "-KolzsgbVnMc4s7lr-c-": {
          "id": 22,
          "version": 42,
          "detail": "this is a test",
          "level2": {
            "level21": "22",
            "level22": true
          }
        }
      }
    }
  }
}

Tips for further needs

When your database gets bigger, a GET request at the root level may result in a too_big error. In such a case, add the shallow=true parameter to GET requests to browse your data. The responses then only contain sub-levels keys of the requested level, without the whole data of each sub-level.

Example:

$ curl -X GET "https://io.datasync.orange.com/base/test-rest.json?shallow=true&print=pretty"

Server response:

{
  "main": true,
  "history": true
}

Security of your data

Easy way with a secret key

For the moment all your data is completely accessible from the Web for all people knowing the name of your [[service]] application. To secure access of your data, [[service]] allows you to define security rules for each part of your data model. These rules are then permanently checked by [[service]] servers. Security rules configuration is accessible via the security tab of your application in the [[console]].

To begin to test the security rules, a first and easy thing to do is to remove all read and write rights (by default, all data are accessible):

{
  "rules": {
    ".read": false,
    ".write": false
  }
}

Then, if you try a GET (or PUT), you will have a permission denied:
{"error":"Permission denied Get on / ","status":"permission_denied","success":false}

To enable your application to send data to your [[service]] database, we will use a secret key. This key permit the read/write actions on the data even if security rules forbid them (it's like a "root" right, then be careful, With great power, comes great responsibility ).

Go to the authentication tab. Add a new key (beware, the default key is not easily revocable, so instead, generate a new one) with the add a secret buton. Then, copy the key visible with the show button.

Now you just have to put the key in the auth parameters of the http requests to access your data:

curl -X PUT "https://io.datasync.orange.com/base/test-rest.json?auth=xxxxxxxxxxxxxxxxxxxxx" -d '{"id": 22, "version": 42, "firmware": "1.3.4.2", "level2": {"level21": "22", "level22": true}}'

Or for a GET:

curl -X GET "https://io.datasync.orange.com/base/android-carrier/samsung.json?auth=xxxxxxxxxxxxxxxxxxxxx"

If the key is compromised, you can revoke it (authentication tab: show button, then revoke button)

Une solution simple dans le cadre d'une appli Web ne faisant qu'afficher des données écrites par un serveur (pour lequel on peut imaginer que la clé secréte sera bien gardée), serait de bloquer l'écriture (".write" : false) mais d'autoriser à tout le monde la lecture (".read" : true). Cependant cette solution à un gros inconvénient, il est facile pour quelqu'un connaissant le fonctionnement de [[service]] de récupérer toutes les données de votre application. On conseille donc de vérouiller l'accès en lecture depuis la racine de votre application mais d'autoriser la lecture des sous niveaux, par exemple dans notre cas de test on pourrait écrire les réglès suivantes :

A simple security mode for a web application that only show some data that are produced by a server (for which we can imagine that the secret key will be well secured), is to forbid the write action (".write" : false) and to authorize the read action to all people (".read" : true). The main drawback is that a guy that knows how [[service]] works can easily retrieve all your data. You can also forbid reading at the root level and authorize reading only some parts of the application data, for instance in our test case, it could be something like:

{
  "rules": {
    ".read": false,
    ".write": false,
    "history": {
      ".read": true
    },
    "main": {
      ".read": true
    }
  }
}

A GET at root level will fail but a GET on the /history path will work. Beware it's not enough to secure your data. The best solution is to use users authentication methods offered by [[service]] and then to define related security rules. Please have a look on the related documentations: Authentication and Security.