https://drone.io/bitbucket.org/eodolphi/flask-json-resource/status.png

Flask JSON Resource

Quickly create REST api’s using json-schema.

Minimal Example

from flask import Flask

from flask.ext.pymongo import PyMongo
from json_resource import Schema
from flask.ext.json_resource import API

app = Flask('test')
app.debug = True

db = PyMongo(app)
api = API(app, db)

@api.register()
class TestResource(api.Resource):
    schema = Schema({'id': 'test'})


class TestResourceCollection(api.CollectionResource):
    schema = Schema({'id': 'test-collection'})
    objects = TestResource.objects

Contents:

Installation

Flask JSON resource can be installed using pip:

$ pip install flask_json_resource

For development use the -e flag:

$ pip install -e .

Getting started

First create a flask application and and a flask-pymongo database:

from flask import Flask
from flask.ext import PyMongo
from flask.ext.json_resource import API

app = Flask(__name__)
mongo = PyMongo(app)

Now we can create a API object and initialize it with the app and mongo db:

api = API(app, mongo)

The api object exposes two classes that can be used as base classes for the resources in your api:

@api.register()
class ExampleResource(api.Resource):
    schema = Schema({'id': 'example'})


@api.register()
class ExampleCollection(api.Collection):
    schema = Schema({'id': 'example-collection'})

    objects = ExampleResource.objects

The above code registers an ExampleResource and a ExampleCollection resource with the api. It will register views for these resource and expose the resources using the links described in the schemas of these resources.

The schemas are automatically loaded from the schemas dir in your package.

Response Headers

By default the API will return a content-type header and custom link header for every link defined in the schema:

A user-agent should be able to infer the complete api from the links returned. From this response we can see that the schema of the resource can be found at /schemas/examples. Likewise, a new resource can be created at /examples/

It is possible to control which headers are returned by overwriting the headers property:

@api.register()
class ExampleResource(api.Resource):
    schema = Schema({'id': 'example'})

    @property
    def headers(self):
        """ Allow example resources to be stored for up to 600 seconds."""
        headers = super(ExampleResource, self).headers

        headers['Cache-Control'] = 'max-age=600'

        return headers

Authorization

Resource can be protected using an Authorization object:

import requests

from flask.ext.json_resource import TokenAuthorization, UnAuthorized
from json_resource import Object


class Token(Object):
    def load(self):
        """ Veirfy the token on the server and load the token data."""
        response = requests.get(
            'http://oauth.example/token',
            headers={
                'Authorization': 'Bearer %s' % self['access_token'],
                'Content-type': 'application/json'
            }
        )

        if response.status != 200:
            # Unsuccessfull request. Token must be invalid, so we return
            # 401 response
            raise UnAuthorized('Invalid Token')

        self.update(response.json)
        return self


class Authorization(TokenAuthorization):
    token_class = Token

    def default(self, resource):
        """ Authorizes the request if the user_id of the token matches
        the user_id of the resource.
        """
        return self.token['user_id'] == self['user_id']

    def post(self, resource):
        """ Auhtorize POST request only if `create` is in the scope of this
        token.
        """"
        return 'create' in self.token['scopes']


@api.register(authorization=Authorization):
class ExampleResource(api.Resource):
    schema = Schema({'id': 'example'})

This protects the ExampleResource, so requests to a resource are only possible if the user_id of the token matches the user_id of the resource. Resources can only be created if the token has the create scope.

Schemas

Schemas will be loaded automatically from the schemas directory inside your application. If your application is installed as a package, schemas will also be loaded from <prefix>/var/schemas.

Views

When registering a resource, it is possible to override wich views will be loaded.

@api.register(views=[ExampleView])
class Example(api.Resource):
    schema = Schema({'id': 'test'})

It is also possible to override the views that are registered by setting the default_views attribute:

class BaseResource(api.Resource):
    default_views = [CustomView, CustomCreationView]

A custom view can be created by extending the BaseView object:

from flask.ext.json_resource.views import BaseView
class CustomView(BaseView):
    def get(self, **kwargs):
        # implement custom logic for GET requests here