Collections

A collection belongs to a bucket and stores records.

A collection is a mapping with the following attribute:

  • schema: (optional) a JSON schema to validate the collection records
  • cache_expires: (optional, in seconds) add client cache headers on read-only requests. More details...

Note

By default users are assigned to a bucket that is used for their personal data.

Application can use this default bucket with the default shortcut: ie /buckets/default/collections/contacts will be the current user contacts.

Internally the user default bucket is assigned to an ID that can later be used to share data from a user personnal bucket.

Collections on the “default” bucket are created silently upon first access and therefore don’t need to be set beforehand.

Creating a collection

PUT /buckets/(bucket_id)/collections/(collection_id)
Synopsis:Creates or replaces a collection object.

Requires authentication

A collection is the parent object of records. It can be viewed as a container where records permissions are assigned globally.

Example Request

$ http put http://localhost:8888/v1/buckets/blog/collections/articles --auth="bob:" --verbose
PUT /v1/buckets/blog/collections/articles HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Authorization: Basic Ym9iOg==
Connection: keep-alive
Content-Length: 0
Host: localhost:8888
User-Agent: HTTPie/0.9.2
HTTP/1.1 201 Created
Access-Control-Expose-Headers: Backoff, Retry-After, Alert
Content-Length: 159
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 15:36:34 GMT
Server: waitress

{
    "data": {
        "id": "articles",
        "last_modified": 1434641794149
    },
    "permissions": {
        "write": [
            "basicauth:206691a25679e4e1135f16aa77ebcf211c767393c4306cfffe6cc228ac0886b6"
        ]
    }
}

Note

In order to create only if it does not exist yet, a If-None-Match: * request header can be provided. A 412 Precondition Failed error response will be returned if the record already exists.

Updating a collection

PATCH /buckets/(bucket_id)/collections/(collection_id)
Synopsis:Updates a collection object.

Requires authentication

A collection is the parent object of records. It can be viewed as a container where records permissions are assigned globally.

Example Request

$ echo '{"data": {"fingerprint": "9cae1b2d0f2b7d09bcf5c1bf51544274"}}' | http patch http://localhost:8888/v1/buckets/blog/collections/articles --auth="bob:" --verbose
PATCH /v1/buckets/blog/collections/articles HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Authorization: Basic Ym9iOg==
Connection: keep-alive
Content-Length: 62
Content-Type: application/json
Host: localhost:8888
User-Agent: HTTPie/0.9.2

{
    "data": {
        "fingerprint": "9cae1b2d0f2b7d09bcf5c1bf51544274"
    }
}
HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert
Content-Length: 208
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 15:36:34 GMT
Server: waitress

{
    "data": {
        "id": "articles",
        "last_modified": 1434641794149,
        "fingerprint": "9cae1b2d0f2b7d09bcf5c1bf51544274"
    },
    "permissions": {
        "write": [
            "basicauth:206691a25679e4e1135f16aa77ebcf211c767393c4306cfffe6cc228ac0886b6"
        ]
    }
}

Retrieving an existing collection

GET /buckets/(bucket_id)/collections/(collection_id)
Synopsis:Returns the collection object.

Requires authentication

Example Request

$ http get http://localhost:8888/v1/buckets/blog/collections/articles --auth="bob:" --verbose
GET /v1/buckets/blog/collections/articles 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: 159
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 15:52:31 GMT
Etag: "1434642751314"
Last-Modified: Thu, 18 Jun 2015 15:52:31 GMT
Server: waitress

{
    "data": {
        "id": "articles",
        "last_modified": 1434641794149
    },
    "permissions": {
        "write": [
            "basicauth:206691a25679e4e1135f16aa77ebcf211c767393c4306cfffe6cc228ac0886b6"
        ]
    }
}

Deleting a collection

DELETE /buckets/(bucket_id)/collections/(collection_id)
Synopsis:Deletes a specific collection and everything under it.

Requires authentication

Example Request

$ http delete http://localhost:8888/v1/buckets/blog/collections/articles --auth="bob:" --verbose
DELETE /v1/buckets/blog/collections/articles 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: 71
Content-Type: application/json; charset=UTF-8
Date: Thu, 18 Jun 2015 15:54:02 GMT
Server: waitress

{
    "data": {
        "deleted": true,
        "id": "articles",
        "last_modified": 1434642842010
    }
}

Collection JSON schema

Requires setting kinto.experimental_collection_schema_validation to True.

A JSON schema can optionally be associated to a collection.

Once a schema is set, records will be validated during creation or update.

If the validation fails, a 400 Bad Request error response will be returned.

Note

JSON schema is quite verbose and not an ideal solution for every use-case. However it is universal and supported by many programming languages and environments.

Set or replace a schema

Just modify the schema attribute of the collection object:

Example request

$ echo '{
  "data": {
    "schema": {
      "title": "Blog post schema",
      "type": "object",
      "properties": {
          "title": {"type": "string"},
          "body": {"type": "string"}
      },
      "required": ["title"]
    }
  }
}' | http PATCH "http://localhost:8888/v1/buckets/default/collections/articles" --auth admin: --verbose
PATCH /v1/buckets/default/collections/articles HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Authorization: Basic YWRtaW46
Connection: keep-alive
Content-Length: 236
Content-Type: application/json; charset=utf-8
Host: localhost:8888
User-Agent: HTTPie/0.8.0

{
    "data": {
        "schema": {
            "properties": {
                "body": {
                    "type": "string"
                },
                "title": {
                    "type": "string"
                }
            },
            "required": [
                "title"
            ],
            "title": "Blog post schema",
            "type": "object"
        }
    }
}

Example response

HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert, Content-Length
Content-Length: 300
Content-Type: application/json; charset=UTF-8
Date: Fri, 21 Aug 2015 12:31:40 GMT
Etag: "1440160300818"
Last-Modified: Fri, 21 Aug 2015 12:31:40 GMT
Server: waitress

{
    "data": {
        "id": "articles",
        "last_modified": 1440160300818,
        "schema": {
            "properties": {
                "body": {
                    "type": "string"
                },
                "title": {
                    "type": "string"
                }
            },
            "required": [
                "title"
            ],
            "title": "Blog post schema",
            "type": "object"
        }
    },
    "permissions": {
        "write": [
            "basicauth:780f1ecd9f57b01bef79608b45916d3bddd17f83461ac6240402e0ffff3596c5"
        ]
    }
}

Records validation

Once a schema has been defined, the posted records must match it:

$ echo '{"data": {
    "body": "Fails if no title"
}}' | http POST http://localhost:8888/v1/buckets/blog/collections/articles/records --auth "admin:"
HTTP/1.1 400 Bad Request
Access-Control-Expose-Headers: Backoff, Retry-After, Alert
Content-Length: 192
Content-Type: application/json; charset=UTF-8
Date: Wed, 10 Jun 2015 10:17:01 GMT
Server: waitress

{
    "code": 400,
    "details": [
        {
            "description": "u'title' is a required property",
            "location": "body",
            "name": "title"
        }
    ],
    "errno": 107,
    "error": "Invalid parameters",
    "message": "u'title' is a required property"
}

Schema migrations

Kinto does not take care of schema migrations. But it gives the basics for clients to manage it.

If the validation succeeds, the record will receive a schema field with the schema version (i.e. the collection current last_modified timestamp).

It becomes possible to use this schema field as a filter on the collection records endpoint in order to obtain the records that were not validated against a particular version of the schema.

For example, GET /buckets/default/collections/articles/records?min_schema=123456.

Remove a schema

In order to remove the schema of a collection, just modify the schema field to an empty mapping.

Example request

echo '{"data": {"schema": {}} }' | http PATCH "http://localhost:8888/v1/buckets/default/collections/articles" --auth admin: --verbose
PATCH /v1/buckets/default/collections/articles HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Authorization: Basic YWRtaW46
Connection: keep-alive
Content-Length: 26
Content-Type: application/json; charset=utf-8
Host: localhost:8888
User-Agent: HTTPie/0.8.0

{
    "data": {
        "schema": {}
    }
}

Example response

HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert, Content-Length
Content-Length: 171
Content-Type: application/json; charset=UTF-8
Date: Fri, 21 Aug 2015 12:27:04 GMT
Etag: "1440159981842"
Last-Modified: Fri, 21 Aug 2015 12:26:21 GMT
Server: waitress

{
    "data": {
        "id": "articles",
        "last_modified": 1440159981842,
        "schema": {}
    },
    "permissions": {
        "write": [
            "basicauth:780f1ecd9f57b01bef79608b45916d3bddd17f83461ac6240402e0ffff3596c5"
        ]
    }
}

Collection caching

With the cache_expires attribute on a collection, it is possible to add client cache control response headers for read-only requests. The client (or cache server or proxy) will use them to cache the collection records for a certain amount of time, in seconds.

For example, set it to 3600 (1 hour):

echo '{"data": {"cache_expires": 3600} }' | http PATCH "http://localhost:8888/v1/buckets/default/collections/articles" --auth admin:

From now on, the cache control headers are set for the GET requests:

http  "http://localhost:8888/v1/buckets/default/collections/articles/records" --auth admin:
HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert, Content-Length, Next-Page, Total-Records, Last-Modified, ETag, Cache-Control, Expires, Pragma
Cache-Control: max-age=3600
Content-Length: 11
Content-Type: application/json; charset=UTF-8
Date: Mon, 14 Sep 2015 13:51:47 GMT
Etag: "1442238450779"
Expires: Mon, 14 Sep 2015 14:51:47 GMT
Last-Modified: Mon, 14 Sep 2015 13:47:30 GMT
Server: waitress
Total-Records: 0

{
    "data": [...]
}

If set to 0, the collection records become explicitly uncacheable (no-cache).

echo '{"data": {"cache_expires": 0} }' | http PATCH "http://localhost:8888/v1/buckets/default/collections/articles" --auth admin:
HTTP/1.1 200 OK
Access-Control-Expose-Headers: Backoff, Retry-After, Alert, Content-Length, Next-Page, Total-Records, Last-Modified, ETag, Cache-Control, Expires, Pragma
Cache-Control: max-age=0, must-revalidate, no-cache, no-store
Content-Length: 11
Content-Type: application/json; charset=UTF-8
Date: Mon, 14 Sep 2015 13:54:51 GMT
Etag: "1442238450779"
Expires: Mon, 14 Sep 2015 13:54:51 GMT
Last-Modified: Mon, 14 Sep 2015 13:47:30 GMT
Pragma: no-cache
Server: waitress
Total-Records: 0

{
    "data": []
}

Note

This can also be forced from settings, see configuration section.