Flask-COMBO-JSONAPI

flask-combo-jsonapi actions flask-combo-jsonapi coverage PyPI

Flask-COMBO-JSONAPI is an extension for Flask that adds support for quickly building REST APIs with huge flexibility around the JSON:API 1.0 specification. It is designed to fit the complexity of real life environments so Flask-COMBO-JSONAPI helps you to create a logical abstraction of your data called “resource”. It can interface any kind of ORMs or data storage through the concept of data layers.

Main concepts

Architecture
* JSON:API 1.0 specification: this is a very popular specification for client-server interactions through a JSON-based REST API. It helps you work in a team because it is very precise and sharable. Thanks to this specification your API can offer a lot of features such as a strong structure of request and response, filtering, pagination, sparse fieldsets, including related objects, great error formatting, etc.

* Logical data abstraction: you usually need to expose resources to clients that don’t fit your data table architecture. For example sometimes you don’t want to expose all attributes of a table, compute additional attributes or create a resource that uses data from multiple data storages. Flask-COMBO-JSONAPI helps you create a logical abstraction of your data with Marshmallow / marshmallow-jsonapi so you can expose your data in a very flexible way.

* Data layer: the data layer is a CRUD interface between your resource manager and your data. Thanks to this you can use any data storage or ORM. There is an already full-featured data layer that uses the SQLAlchemy ORM but you can create and use your own custom data layer to use data from your data storage. You can even create a data layer that uses multiple data storage systems and ORMs, send notifications or perform custom actions during CRUD operations.

Features

Flask-COMBO-JSONAPI has many features:

  • Relationship management

  • Powerful filtering

  • Include related objects

  • Sparse fieldsets

  • Pagination

  • Sorting

  • Permission management

  • OAuth support

User’s Guide

This part of the documentation will show you how to get started using Flask-COMBO-JSONAPI with Flask.

A minimal API

from flask import Flask
from flask_combo_jsonapi import Api, ResourceDetail, ResourceList
from flask_sqlalchemy import SQLAlchemy
from marshmallow import pre_load
from marshmallow_jsonapi.flask import Schema
from marshmallow_jsonapi import fields

# Create the Flask application and the Flask-SQLAlchemy object.
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/api_minimal.db'
db = SQLAlchemy(app)


# Create model
class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)


# Create the database.
db.create_all()


# Create schema
class PersonSchema(Schema):
    class Meta:
        type_ = 'person'
        self_view = 'person_detail'
        self_view_kwargs = {'id': '<id>'}
        self_view_many = 'person_list'

    id = fields.Integer(as_string=True, dump_only=True)
    name = fields.String()

    @pre_load
    def remove_id_before_deserializing(self, data, **kwargs):
        """
        We don't want to allow editing ID on POST / PATCH

        Related issues:
        https://github.com/AdCombo/flask-combo-jsonapi/issues/34
        https://github.com/miLibris/flask-rest-jsonapi/issues/193
        """
        if 'id' in data:
            del data['id']
        return data


# Create resource managers
class PersonList(ResourceList):
    schema = PersonSchema
    data_layer = {
        'session': db.session,
        'model': Person,
    }


class PersonDetail(ResourceDetail):
    schema = PersonSchema
    data_layer = {
        'session': db.session,
        'model': Person,
    }


# Create the API object
api = Api(app)
api.route(PersonList, 'person_list', '/persons')
api.route(PersonDetail, 'person_detail', '/persons/<int:id>')

# Start the flask loop
if __name__ == '__main__':
    app.run()

This example provides the following API structure:

URL

method

endpoint

Usage

/persons

GET

person_list

Get a collection of persons

/persons

POST

person_list

Create a person

/persons/<int:person_id>

GET

person_detail

Get person details

/persons/<int:person_id>

PATCH

person_detail

Update a person

/persons/<int:person_id>

DELETE

person_detail

Delete a person

Request:

POST /persons HTTP/1.1
Content-Type: application/vnd.api+json

{
  "data": {
    "type": "person",
    "attributes": {
        "name": "John"
    }
  }
}

Response:

HTTP/1.1 201 Created
Content-Type: application/vnd.api+json

{
  "data": {
    "attributes": {
      "name": "John"
    },
    "id": "1",
    "links": {
      "self": "/persons/1"
    },
    "type": "person"
  },
  "jsonapi": {
    "version": "1.0"
  },
  "links": {
    "self": "/persons/1"
  }
}

Request:

GET /persons/1 HTTP/1.1
Content-Type: application/vnd.api+json

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "data": {
    "attributes": {
      "name": "John"
    },
    "id": "1",
    "links": {
      "self": "/persons/1"
    },
    "type": "person"
  },
  "jsonapi": {
    "version": "1.0"
  },
  "links": {
    "self": "/persons/1"
  }
}

Request:

GET /persons HTTP/1.1
Content-Type: application/vnd.api+json

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "data": [
    {
      "attributes": {
        "name": "John"
      },
      "id": "1",
      "links": {
        "self": "/persons/1"
      },
      "type": "person"
    }
  ],
  "jsonapi": {
    "version": "1.0"
  },
  "links": {
    "self": "http://localhost:5000/persons"
  },
  "meta": {
    "count": 1
  }
}

Request:

PATCH /persons/1 HTTP/1.1
Content-Type: application/vnd.api+json

{
  "data": {
    "id": 1,
    "type": "person",
    "attributes": {
        "name": "Sam"
    }
  }
}

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "data": {
    "attributes": {
      "name": "Sam"
    },
    "id": "1",
    "links": {
      "self": "/persons/1"
    },
    "type": "person"
  },
  "jsonapi": {
    "version": "1.0"
  },
  "links": {
    "self": "/persons/1"
  }
}

Request:

DELETE /persons/1 HTTP/1.1
Content-Type: application/vnd.api+json

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "jsonapi": {
    "version": "1.0"
  },
  "meta": {
    "message": "Object successfully deleted"
  }
}

API Reference

If you are looking for information on a specific function, class or method, this part of the documentation is for you.