Skip to main content

falcon REST done with grace

Project description

Build Status Coverage Status Documentation Status

graceful

graceful is elegant Python REST toolkit built on top of falcon. It is highly inspired by Django REST framework - mostly by how object serialization is done but more emphasis here is put on API to be self-descriptive.

Features:

  • generic classes for list and single object resources

  • simple but extendable pagination

  • structured responses with content/meta separation

  • declarative fields and parameters

  • self-descriptive-everything: API description accessible both in python and through OPTIONS requests

  • painless validation

  • 100% tests coverage

  • falcon>=0.3.0 (tested up to 1.0.x)

  • python3 exclusive (tested from 3.3 to 3.5)

There is no community behind graceful yet but I hope we will build one someday with your help. Anyway there is a mailing list on Librelist. Just send an email to graceful@librelist.com and you’re subscribed.

python3 only

Important: graceful is python3 exclusive because right now should be a good time to forget about python2. There are no plans for making graceful python2 compatibile although it would be pretty straightforward do do so with existing tools (like six).

usage

For extended tutorial and more information please refer to guide included in documentation.

Anyway here is simple example of working API made made with graceful:

import falcon

from graceful.serializers import BaseSerializer
from graceful.fields import IntField, RawField
from graceful.parameters import StringParam
from graceful.resources.generic import (
    RetrieveAPI,
    PaginatedListAPI,
)

api = application = falcon.API()

# lets pretend that this is our backend storage
CATS_STORAGE = [
    {"id": 0, "name": "kitty", "breed": "saimese"},
    {"id": 1, "name": "lucie", "breed": "maine coon"},
    {"id": 2, "name": "molly", "breed": "sphynx"},
]


# this is how we represent cats in our API
class CatSerializer(BaseSerializer):
    id = IntField("cat identification number", read_only=True)
    name = RawField("cat name")
    breed = RawField("official breed name")


class Cat(RetrieveAPI):
    """
    Single cat identified by its id
    """
    serializer = CatSerializer()

    def get_cat(self, cat_id):
        try:
            return [
                cat for cat in CATS_STORAGE if cat['id'] == int(cat_id)
            ][0]
        except IndexError:
            raise falcon.HTTPNotFound


    def retrieve(self, params, meta, **kwargs):
        cat_id = kwargs['cat_id']
        return self.get_cat(cat_id)

class CatList(PaginatedListAPI):
    """
    List of all cats in our API
    """
    serializer = CatSerializer()

    breed = StringParam("set this param to filter cats by breed")

    def list(self, params, meta, **kwargs):
        if 'breed' in params:
            filtered = [
                cat for cat in CATS_STORAGE
                if cat['breed'] == params['breed']
            ]
            return filtered
        else:
            return CATS_STORAGE

api.add_route("/v1/cats/{cat_id}", Cat())
api.add_route("/v1/cats/", CatList())

Assume this code is in python module named example.py. Now run it with gunicorn:

gunicorn -b localhost:8888 example

And you’re ready to query it (here with awesome httpie tool):

$ http localhost:8888/v0/cats/?breed=saimese
HTTP/1.1 200 OK
Connection: close
Date: Tue, 16 Jun 2015 08:43:05 GMT
Server: gunicorn/19.3.0
content-length: 116
content-type: application/json

{
    "content": [
        {
            "breed": "saimese",
            "id": 0,
            "name": "kitty"
        }
    ],
    "meta": {
        "params": {
            "breed": "saimese",
            "indent": 0
        }
    }
}

Or access API description issuing OPTIONS request:

$ http OPTIONS localhost:8888/v0/cats
HTTP/1.1 200 OK
Connection: close
Date: Tue, 16 Jun 2015 08:40:00 GMT
Server: gunicorn/19.3.0
allow: GET, OPTIONS
content-length: 740
content-type: application/json

{
    "details": "List of all cats in our API",
    "fields": {
        "breed": {
            "details": "official breed name",
            "label": null,
            "spec": null,
            "type": "string"
        },
        "id": {
            "details": "cat identification number",
            "label": null,
            "spec": null,
            "type": "int"
        },
        "name": {
            "details": "cat name",
            "label": null,
            "spec": null,
            "type": "string"
        }
    },
    "methods": [
        "GET",
        "OPTIONS"
    ],
    "name": "CatList",
    "params": {
        "breed": {
            "default": null,
            "details": "set this param to filter cats by breed",
            "label": null,
            "required": false,
            "spec": null,
            "type": "string"
        },
        "indent": {
            "default": "0",
            "details": "JSON output indentation. Set to 0 if output should not be formated.",
            "label": null,
            "required": false,
            "spec": null,
            "type": "integer"
        }
    },
    "path": "/v0/cats",
    "type": "list"
}

contributing

Any contribution is welcome. Issues, suggestions, pull requests - whatever. There is only short set of rules that guide this project development you should be aware of before submitting a pull request:

  • Only requests that have passing CI builds (Travis) will be merged.

  • Code is checked with flakes8 and pydocstyle during build so this implicitely means that compliance with PEP-8 and PEP-257 are mandatory.

  • No changes that decrease coverage will be merged.

One thing: if you submit a PR please do not rebase it later unless you are asked for that explicitely. Reviewing pull requests that suddenly had their history rewritten just drives me crazy.

license

See LICENSE file.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

graceful-0.2.0.tar.gz (23.9 kB view details)

Uploaded Source

Built Distribution

graceful-0.2.0-py2.py3-none-any.whl (58.1 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file graceful-0.2.0.tar.gz.

File metadata

  • Download URL: graceful-0.2.0.tar.gz
  • Upload date:
  • Size: 23.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for graceful-0.2.0.tar.gz
Algorithm Hash digest
SHA256 8c0ae8f659f8208ef712cf04296485ddf2b7bf57a825d607708b6aa82a30d0c6
MD5 ad39025742af357fe1de7aa106ed64e8
BLAKE2b-256 c29f6a71ca6b4b0a47f1362e7cfd36d8b9c42cc79147398847a596970f8de147

See more details on using hashes here.

File details

Details for the file graceful-0.2.0-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for graceful-0.2.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 278974c943633a45a74825a118c245bc99e7f2a6d7758d77d8c1709ebaf68c2b
MD5 ce1dcacb12243c9e9d6d6a86f6be4e55
BLAKE2b-256 ae989a3a4c84966b5d4accb7cda37a46328ec6138e3b0fa30af3aa12ec1d17d9

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page