Metadata-Version: 2.1
Name: cerasus
Version: 0.0.1
Summary: Simple quickstarter/dispatcher for ASGI apps based on Hypercorn with Request/Response objects from Starlette.
Home-page: https://github.com/amateur80lvl/cerasus
Author: amateur80lvl
Author-email: amateur80lvl@gmail.com
Keywords: asgi,asyncio
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Environment :: Web Environment
Classifier: Programming Language :: Python
Classifier: Operating System :: OS Independent
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: hypercorn
Requires-Dist: starlette
Requires-Dist: uvloop

# Cerasus

Cerasus is a simple dispatcher and quickstart function for ASGI apps based on Hypercorn
with Request/Response objects from Starlette.

The dispatcher uses a mapping like this:

``` python
{
    'GET': {
        '': webapp.index,
        '/': webapp.index,
        '/items/get': webapp.api.items.get
    },
    'POST': {
        '/items/add': webapp.api.items.add
    }
}
```

No REST. No Routes. What can be simpler?

The mapping is constructed by `expose` decorators. Here's an example that matches the mapping above:

``` python
from cerasus import expose, quickstart
from starlette.requests import Request
from starlette.responses import HTMLResponse, JSONResponse

class APIError(Exception):

    def __init__(self, status_code, description):
        self.status_code = status_code
        self.description = description

class Items:

    @expose
    async def get(self, request):
        items = []
        # get items
        # ...
        return JSONResponse(dict(status='success', items=items))

    @expose(methods='POST')
    async def add(self, request):
        item = await request.json()
        # add item
        # ...
        return JSONResponse(dict(status='success'))

class Api:
    # Customized error handling for API.
    # Error handlers can be either coroutines that return Starlette Response objects, or just objects:
    _undefined_method = JSONResponse(dict(status='error', description='Method not allowed'), status_code=405)
    _undefined_handler = JSONResponse(dict(status='error', description='Bad endpoint'), status_code=404)

    async def _exception_handler(self, request, exc):
        return JSONResponse(dict(status='error', description=exc.description), status_code=exc.status_code)

    # Note that children "inherit" error responses, i.e. we do not define them for Items
    items = Items()

class Webapp:
    api = Api()

    @expose(name='/')
    async def index(self, request):
        return HTMLResponse('<h1>Hello</h1>')

async def open_db():
    pass

async def close_db():
    pass

if __name__ == "__main__":
    quickstart(
        Api(),
        {
            'bind': ['127.0.0.1:12345']
            'alpn_protocols': ['h2']
        },
        base_urlpath = '/',
        on_startup = open_db,
        on_shutdown = close_db
    )
```
