Kinto-Core provides a basic component to build resource oriented APIs. In most cases, the main customization consists in defining the schema of the records for this resource.

Full example

import colander

from kinto.core import resource
from kinto.core import utils

class BookmarkSchema(resource.ResourceSchema):
    url = colander.SchemaNode(colander.String(), validator=colander.url)
    title = colander.SchemaNode(colander.String())
    favorite = colander.SchemaNode(colander.Boolean(), missing=False)
    device = colander.SchemaNode(colander.String(), missing='')

    class Options:
        readonly_fields = ('device',)

class Bookmark(resource.Resource):
    schema = BookmarkSchema

    def process_object(self, new, old=None):
        new = super().process_object(new, old)
        if new['device'] != old['device']:
            new['device'] = self.request.headers.get('User-Agent')

        return new

See the ReadingList and Kinto projects source code for real use cases.


By default, a resource defines two URLs:

  • /{classname}s for the list of records
  • /{classname}s/{id} for single records

Since adding an s suffix for the plural form might not always be relevant, URLs can be specified during registration:

class Bookmark(resource.Resource):
    schema = BookmarkSchema


The same resource can be registered with different URLs.


Override the base schema to add extra fields using the Colander API.

class Movie(resource.ResourceSchema):
    director = colander.SchemaNode(colander.String())
    year = colander.SchemaNode(colander.Int(),
    genre = colander.SchemaNode(colander.String(),
                                validator=colander.OneOf(['Sci-Fi', 'Comedy']))

See the resource schema options to define schema-less resources or specify rules like readonly fields.

HTTP methods and options

In order to specify which HTTP verbs (GET, PUT, PATCH, …) are allowed on the resource, as well as specific custom Pyramid (or cornice) view arguments, refer to the viewset section.


When a record is created/deleted in a resource, an event is sent. See the dedicated section about notifications to plug events in your Pyramid/Kinto-Core application or plugin.


Plug custom model

In order to customize the interaction of a HTTP resource with its storage, a custom model can be plugged-in:

from kinto.core import resource

class TrackedModel(resource.Model):
    def create_record(self, record, parent_id=None):
        record = super().create_record(record, parent_id)
        trackid = index.track(record)
        record['trackid'] = trackid
        return record

class Payment(resource.Resource):
    default_model = TrackedModel


With the default model and storage backend, Kinto-Core does not support complex relations.

However, it is possible to plug a custom model class, that will take care of saving and retrieving records with relations.


This part deserves more love, please come and discuss!

In Pyramid views

In Pyramid views, a request object is available and allows to use the storage configured in the application:

from kinto.core import resource

def view(request):
    registry = request.registry

    flowers = resource.Model(,

    flowers.create_object({'name': 'Jonquille', 'size': 30})
    flowers.create_object({'name': 'Amapola', 'size': 18})

    min_size = resource.Filter('size', 20, resource.COMPARISON.MIN)
    objects = flowers.get_objects(filters=[min_size])


Outside views

Outside views, an application context has to be built from scratch.

As an example, let’s build a code that will copy a collection into another:

from kinto.core import resource, DEFAULT_SETTINGS
from pyramid import Configurator

config = Configurator(settings=DEFAULT_SETTINGS)
    'kinto.storage_backend': ''
    'kinto.storage_url': 'postgresql://user:[email protected]:5432/dbname'
kinto.core.initialize(config, '0.0.1')

local = resource.Model(,

remote = resource.Model(,

records, total = in remote.get_records():
for record in records:

Custom record ids

By default, records ids are UUID4.

A custom record ID generator can be set globally in Configuration, or at the resource level:

from kinto.core import resource
from kinto.core import utils
from import generators

class MsecId(generators.Generator):
    def __call__(self):
        return '%s' % utils.msec_time()

class Mushroom(resource.Resource):
    def __init__(request):
        self.model.id_generator = MsecId()

Python API