Metadata-Version: 1.1
Name: graceful
Version: 0.6.2
Summary: Elegant Python REST toolkit built on top of falcon
Home-page: https://github.com/swistakm/graceful
Author: Michał Jaworski
Author-email: swistakm@gmail.com
License: BSD
Description-Content-Type: text/markdown
Description: [![PyPI](https://img.shields.io/pypi/v/graceful.svg)](https://pypi.python.org/pypi/graceful/)
        [![PyPI](https://img.shields.io/pypi/pyversions/graceful.svg)](https://pypi.python.org/pypi/graceful/)
        [![Build Status](https://travis-ci.org/swistakm/graceful.svg?branch=master)](https://travis-ci.org/swistakm/graceful)
        [![Coverage Status](https://coveralls.io/repos/swistakm/graceful/badge.svg?branch=master)](https://coveralls.io/r/swistakm/graceful?branch=master)
        [![Documentation Status](https://readthedocs.org/projects/graceful/badge/?version=latest)](https://graceful.readthedocs.io/en/latest/)
        [![Join the chat at https://gitter.im/graceful-for-falcon/Lobby](https://badges.gitter.im/graceful-for-falcon/Lobby.svg)](https://gitter.im/graceful-for-falcon/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
        
        # graceful
        
        `graceful` is an elegant Python REST toolkit built on top of
        [falcon](http://github.com/falconry/falcon) framework. It is highly inspired
        by [Django REST framework](http://www.django-rest-framework.org/) - 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
        * simple but extendable authentication and authorization
        * 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.4.x)
        * python3 exclusive (tested from 3.3 to 3.6)
        
        Community behind graceful is starting to grow but we don't have any mailing
        list yet. There was one on [Librelist](http://librelist.com/browser/graceful)
        but no one used it and it seems that librelist became dead (see GitHub
        issue [#36](https://github.com/swistakm/graceful/issues/36)). For now let's use
        gitter chat until we decide on something new.
        Chat is available [here](https://gitter.im/graceful-for-falcon/Lobby).
        
        
        ## 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 compatible although it would be pretty straightforward to do so with
        existing tools (like six).
        
        ## usage
        For extended tutorial and more information please refer to
        [guide](https://graceful.readthedocs.org/en/latest/guide/) included in
        documentation. 
        
        Anyway here is simple example of working API made made with `graceful`:
        
        ```python
        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](https://github.com/benoitc/gunicorn):
        
            gunicorn -b localhost:8888 example
        
        And you're ready to query it (here with awesome [httpie](http://httpie.org)
        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
          implicitly means that compliance with PEP-8 and PEP-257 is 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 explicitly. Reviewing pull requests that suddenly had
        their history rewritten just drives me crazy.
        
        
        ## license
        
        See `LICENSE` file.
        
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
