Records

Records belong to a collection. It is the data being stored and synchronised.

A record is a mapping with the following attributes:

  • data: attributes of the record object
    • id: the record object id
    • last_modified: the timestamp of the last modification
  • permissions: the ACLs for the collection object

Uploading a record

POST /buckets/(bucket_id)/collections/(collection_id)/records
synopsis:Store a record in the collection. The ID will be assigned automatically.

Requires authentication

Example Request

$ echo '{"data": {"foo": "bar"}}' | http post http://localhost:8888/v1/buckets/blog/collections/articles/records --auth="bob:p4ssw0rd" --verbose
POST /v1/buckets/blog/collections/articles/records HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Authorization: Basic Ym9iOg==
Connection: keep-alive
Content-Length: 25
Content-Type: application/json
Host: localhost:8888
User-Agent: HTTPie/0.9.2

{
    "data": {
        "foo": "bar"
    }
}

Example Response

HTTP/1.1 201 Created
Access-Control-Expose-Headers: Backoff, Retry-After, Alert
Content-Length: 199
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 17:02:23 GMT
Server: waitress

{
    "data": {
        "foo": "bar",
        "id": "89881454-e4e9-4ef0-99a9-404d95900352",
        "last_modified": 1434646943915
    },
    "permissions": {
        "write": [
            "account:bob"
        ]
    }
}

If the If-Match: "<timestamp>" request header is provided as described in the section about timestamps, and if the list has changed meanwhile, a 412 Precondition Failed error is returned.

If the If-None-Match: * request header is provided, and if the provided data contains an id field, and if there is already an existing object with this id, a 412 Precondition Failed error is returned.

Important

If the posted object has an id field, it will be taken into account.

However, if an object already exists with the same id, a 200 OK response is returned with the existing object in body (instead of 201 Created). See https://github.com/Kinto/kinto/issues/140

Validation

If the posted values are invalid (e.g. field value is not an integer) an error response is returned with 400 Bad Request.

See details on error responses.

Permissions

In the JSON request payloads, an optional permissions attribute can be provided.

The current user id is always added among the write principals.

See Permissions request payload.

HTTP Status Codes

  • 200 OK: This object already exists, the one stored on the database is returned
  • 201 Created: The object was created
  • 400 Bad Request: The request body is invalid
  • 401 Unauthorized: The request is missing authentication headers
  • 403 Forbidden: The user is not allowed to perform the operation, or the resource is not accessible
  • 406 Not Acceptable: The client doesn’t accept supported responses Content-Type
  • 412 Precondition Failed: List has changed since value in If-Match header
  • 415 Unsupported Media Type: The client request was not sent with a correct Content-Type

Replacing a record

PUT /buckets/(bucket_id)/collections/(collection_id)/records/(record_id)
Synopsis:Create or update a record in the collection.

The POST body is a JSON mapping containing:

  • data: the fields of the record;
  • permissions: optional a json dict containing the permissions for the record to be created.

Requires authentication

Example Request

$ echo '{"data": {"foo": "baz"}}' | http put http://localhost:8888/v1/buckets/blog/collections/articles/records/89881454-e4e9-4ef0-99a9-404d95900352 --auth="bob:p4ssw0rd" --verbose
PUT /v1/buckets/blog/collections/articles/records/89881454-e4e9-4ef0-99a9-404d95900352 HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Authorization: Basic Ym9iOg==
Connection: keep-alive
Content-Length: 25
Content-Type: application/json
Host: localhost:8888
User-Agent: HTTPie/0.9.2

{
  "data": {
      "foo": "baz"
  }
}

Example Response

HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert
Content-Length: 199
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 17:16:22 GMT
Server: waitress

{
  "data": {
      "foo": "baz",
      "id": "89881454-e4e9-4ef0-99a9-404d95900352",
      "last_modified": 1434647782623
  },
  "permissions": {
      "write": [
          "account:bob"
      ]
  }
}

Validation and conflicts behaviour is similar to creating objects (POST).

If the If-Match: "<timestamp>" request header is provided as described in the section about timestamps, and if the object has changed meanwhile, a 412 Precondition Failed error is returned.

If the If-None-Match: * request header is provided and if there is already an existing object with this id, a 412 Precondition Failed error is returned.

Permissions

In the JSON request payloads, at least one of data and permissions must be provided. Permissions can thus be replaced independently from data.

In the case of creation, if only permissions is provided, an empty object is created.

The current user id is always added among the write principals.

See Permissions request payload.

HTTP Status Code

  • 201 Created: The object was created
  • 200 OK: The object was replaced
  • 400 Bad Request: The request body is invalid
  • 401 Unauthorized: The request is missing authentication headers
  • 403 Forbidden: The user is not allowed to perform the operation, or the resource is not accessible
  • 406 Not Acceptable: The client doesn’t accept supported responses Content-Type.
  • 412 Precondition Failed: Record was changed or deleted since value in If-Match header.
  • 415 Unsupported Media Type: The client request was not sent with a correct Content-Type.

Updating a record

PATCH /buckets/(bucket_id)/collections/(collection_id)/records/(record_id)
Synopsis:Update a record in the collection. Specify only the fields to be modified (all the rest will remain intact).

Requires authentication

Example Request

$ echo '{"data": {"status": "done"}}' | http patch http://localhost:8888/v1/buckets/blog/collections/articles/records/89881454-e4e9-4ef0-99a9-404d95900352 --auth="bob:p4ssw0rd" --verbose
PATCH /v1/buckets/blog/collections/articles/records/89881454-e4e9-4ef0-99a9-404d95900352 HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Authorization: Basic Ym9iOg==
Connection: keep-alive
Content-Length: 25
Content-Type: application/json
Host: localhost:8888
User-Agent: HTTPie/0.9.2

{
  "data": {
      "status": "done"
  }
}

Example Response

HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert
Content-Length: 211
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 17:19:56 GMT
Server: waitress

{
  "data": {
      "status": "done",
      "title": "Midnight in Paris",
      "id": "89881454-e4e9-4ef0-99a9-404d95900352",
      "last_modified": 1434647996969
  },
  "permissions": {
      "write": [
          "account:bob"
      ]
  }
}

If the object is missing (or already deleted), a 404 Not Found is returned only if the user has write access to the object parent, otherwise a 403 Forbidden is returned to avoid leaking information about non-accessible objects. The consumer might decide to ignore it.

If the If-Match: "<timestamp>" request header is provided as described in the section about timestamps, and if the object has changed meanwhile, a 412 Precondition Failed error is returned.

Note

last_modified is updated to the current server timestamp, only if a field value was changed.

Attributes merge

The provided values are merged with the existing object. For example:

  • {"a":"b"} + {"a":"c"}{"a":"c"}
  • {"a":"b"} + {"b":"c"}{"a":"b", "b":"c"}
  • {"a":"b"} + {"a":null}{"a":null} : attributes can’t be removed with patch
  • {"a": {"b":"c"}} + {"a":{"d":"e"}}{"a":{"d":"e"}} : sub-objects are replaced, not merged

JSON merge is currently supported using Content-Type: application/merge-patch+json. This provides support to merging sub-objects and removing attibutes. For example:

  • {"a":"b"} + {"a":null}{}
  • {"a": {"b":"c"}} + {"a":{"d":"e"}}{"a":{"b":"c", "d":"e"}}
  • {} + {"a":{"b":{"c":null}}}{"a":{"b":{}}}

Light response body

If a Response-Behavior request header is set to light, only the fields whose value was changed are returned. If set to diff, only the fields whose value became different than the one provided are returned.

JSON Patch Operations

JSON-Patch is a way to define a sequence of operations to be applied on a JSON object.

It’s possible to use JSON-Patch by sending the request header Content-Type: application/json-patch+json.

When using this request header, the body should contain a list of operations, for example:

[
    { "op": "test", "path": "data/a", "value": "foo" },
    { "op": "remove", "path": "/data/a" },
    { "op": "add", "path": "/data/b", "value": [ "foo", "bar" ] },
    { "op": "replace", "path": "/data/b", "value": 42 },
    { "op": "move", "from": "/data/a", "path": "/data/c" },
    { "op": "copy", "from": "/data/b", "path": "/data/d" }
]

For more information about each operation, please refer to JSON-Patch Specification.

This is very useful when altering permissions since there is no need to get the current value before adding some principal to the list.

Permissions

When permissions are modified, the same behaviour used for the body is expected. But notice thought that there are some permissions specific behaviours, such as:

  1. The current user id is always added among the write principals.
  2. Value is not used on permission JSON Patch operations and can be omitted.
[
    { "op": "test", "path": "/permissions/read/fxa:alice" },
    { "op": "add", "path": "/permissions/read/system.Everyone" },
    { "op": "remove", "path": "/permissions/read/fxa:bob" }
]
  1. On JSON Merge operations, null values can be used to remove all principals from a specific permission level. As a consequence, using null for permissions on other types of patch operations is considered a no-op.

For more information on permissions, see Permissions request payload.

HTTP Status Codes

  • 200 OK: The object was modified
  • 400 Bad Request: The request body is invalid, or a read-only field was modified
  • 401 Unauthorized: The request is missing authentication headers
  • 403 Forbidden: The user is not allowed to perform the operation, or the resource is not accessible
  • 404 Not Found: The object does not exist or was deleted
  • 406 Not Acceptable: The client doesn’t accept supported responses Content-Type.
  • 412 Precondition Failed: Record changed since value in If-Match header
  • 415 Unsupported Media Type: The client request was not sent with a correct Content-Type.

Retrieving stored records

GET /buckets/(bucket_id)/collections/(collection_id)/records
Synopsis:Retrieve all the records in the collection.

Requires authentication

Example Request

$ http get http://localhost:8888/v1/buckets/blog/collections/articles/records --auth="bob:p4ssw0rd" --verbose
GET /v1/buckets/blog/collections/articles/records HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Authorization: Basic Ym9iOg==
Connection: keep-alive
Host: localhost:8888
User-Agent: HTTPie/0.9.2
HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert, Next-Page, Total-Objects, Last-Modified, ETag
Content-Length: 110
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 17:24:38 GMT
Etag: "1434648278603"
Last-Modified: Thu, 18 Jun 2015 17:24:38 GMT
Server: waitress
Total-Objects: 1

{
    "data": [
        {
            "baz": "bar",
            "foo": "baz",
            "id": "89881454-e4e9-4ef0-99a9-404d95900352",
            "last_modified": 1434647996969
        }
    ]
}

Retrieving a specific record

GET /buckets/(bucket_id)/collections/(collection_id)/records/(record_id)
Synopsis:Retrieve a specific record by its ID.

Requires authentication

Example Request

$ http get http://localhost:8888/v1/buckets/blog/collections/articles/records/89881454-e4e9-4ef0-99a9-404d95900352 --auth="bob:p4ssw0rd" --verbose
GET /v1/buckets/blog/collections/articles/records/89881454-e4e9-4ef0-99a9-404d95900352 HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Authorization: Basic Ym9iOg==
Connection: keep-alive
Host: localhost:8888
User-Agent: HTTPie/0.9.2

Example Response

HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert, Last-Modified, ETag
Content-Length: 211
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 17:29:59 GMT
Etag: "1434648599199"
Last-Modified: Thu, 18 Jun 2015 17:29:59 GMT
Server: waitress

{
    "data": {
        "baz": "bar",
        "foo": "baz",
        "id": "89881454-e4e9-4ef0-99a9-404d95900352",
        "last_modified": 1434647996969
    },
    "permissions": {
        "write": [
            "account:bob"
        ]
    }
}

Delete stored records

DELETE /buckets/(bucket_id)/collections/(collection_id)/records
Synopsis:Delete all the records in the collection.

Requires authentication

Example Request

$ http delete http://localhost:8888/v1/buckets/blog/collections/articles/records --auth="bob:p4ssw0rd" --verbose
DELETE /v1/buckets/blog/collections/articles/records HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Authorization: Basic Ym9iOg==
Connection: keep-alive
Host: localhost:8888
User-Agent: HTTPie/0.9.2

Example Response

HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert, Last-Modified, ETag
Content-Length: 211
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 17:29:59 GMT
Etag: "1434648599199"
Last-Modified: Thu, 18 Jun 2015 17:29:59 GMT
Server: waitress

{
    "data": [{
        "deleted": true,
        "id": "89881454-e4e9-4ef0-99a9-404d95900352",
        "last_modified": 1434648749173
    }]
}

Deleting a single record

DELETE /buckets/(bucket_id)/collections/(collection_id)/records/(record_id)
Synopsis:Delete a record by its ID.

Example Request

$ http delete http://localhost:8888/v1/buckets/blog/collections/articles/records/89881454-e4e9-4ef0-99a9-404d95900352 --auth="bob:p4ssw0rd" --verbose
DELETE /v1/buckets/blog/collections/articles/records/89881454-e4e9-4ef0-99a9-404d95900352 HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Authorization: Basic Ym9iOg==
Connection: keep-alive
Content-Length: 0
Host: localhost:8888
User-Agent: HTTPie/0.9.2

Example Response

HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert
Content-Length: 99
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 17:32:29 GMT
Server: waitress

{
    "data": {
        "deleted": true,
        "id": "89881454-e4e9-4ef0-99a9-404d95900352",
        "last_modified": 1434648749173
    }
}