aiohttp-apispec


Nameaiohttp-apispec JSON
Version 2.2.3 PyPI version JSON
download
home_pagehttps://github.com/maximdanilchenko/aiohttp-apispec
SummaryBuild and document REST APIs with aiohttp and apispec
upload_time2022-03-01 14:35:30
maintainer
docs_urlNone
authorDanilchenko Maksim
requires_python>=3.5
licenseMIT
keywords aiohttp marshmallow apispec swagger
VCS
bugtrack_url
requirements aiohttp apispec webargs jinja2
Travis-CI
coveralls test coverage No coveralls.
            <h1 align="center">aiohttp-apispec</h1>
<p align="center">Build and document REST APIs with <a href="https://github.com/aio-libs/aiohttp">aiohttp</a> and <a href="https://github.com/marshmallow-code/apispec">apispec</a></p>

<p align="center">
  <a href="https://pypi.python.org/pypi/aiohttp-apispec"><img src="https://badge.fury.io/py/aiohttp-apispec.svg" alt="Pypi"></a>
  <a href="https://github.com/maximdanilchenko/aiohttp-apispec/graphs/contributors"><img src="https://img.shields.io/github/contributors/maximdanilchenko/aiohttp-apispec.svg" alt="Contributors"></a>
  <a href="https://pepy.tech/project/aiohttp-apispec"><img src="https://pepy.tech/badge/aiohttp-apispec" alt="Downloads"></a>
</p>

<p align="center">
  <a href="https://travis-ci.org/maximdanilchenko/aiohttp-apispec"><img src="https://travis-ci.org/maximdanilchenko/aiohttp-apispec.svg" alt="build status"></a>
  <a href="https://aiohttp-apispec.readthedocs.io/en/latest/?badge=latest"><img src="https://readthedocs.org/projects/aiohttp-apispec/badge/?version=latest" alt="[docs]"></a>
  <a href="https://codecov.io/gh/maximdanilchenko/aiohttp-apispec"><img src="https://codecov.io/gh/maximdanilchenko/aiohttp-apispec/branch/master/graph/badge.svg" alt="[codcov]"></a>
  <a href="https://github.com/ambv/black"><img src="https://img.shields.io/badge/code%20style-black-000000.svg" alt="Code style: black"></a>
</p>

<p>

```aiohttp-apispec``` key features:
- ```docs``` and ```request_schema``` decorators 
to add swagger spec support out of the box;
- ```validation_middleware``` middleware to enable validating 
with marshmallow schemas from those decorators;
- **SwaggerUI** support.
- *New from version 2.0* -  ```match_info_schema```, ```querystring_schema```, 
```form_schema```, ```json_schema```, ```headers_schema``` and ```cookies_schema``` 
decorators for specific request parts validation. 
Look [here](#more-decorators) for more info.

```aiohttp-apispec``` api is fully inspired by ```flask-apispec``` library

## Contents

- [Install](#install)
- [Quickstart](#quickstart)
- [Adding validation middleware](#adding-validation-middleware)
- [More decorators](#more-decorators)
- [Custom error handling](#custom-error-handling)
- [Build swagger web client](#build-swagger-web-client)
- [Versioning](#versioning)


## Install

```
pip install aiohttp-apispec
```

## Quickstart

*Also you can read [blog post](https://dmax.blog/how_to_easily_build_modern_web_apis_with_python_and_aiohttp) about quickstart with aiohttp-apispec*

```Python
from aiohttp_apispec import (
    docs,
    request_schema,
    setup_aiohttp_apispec,
)
from aiohttp import web
from marshmallow import Schema, fields


class RequestSchema(Schema):
    id = fields.Int()
    name = fields.Str(description="name")

@docs(
    tags=["mytag"],
    summary="Test method summary",
    description="Test method description",
)
@request_schema(RequestSchema(strict=True))
async def index(request):
    return web.json_response({"msg": "done", "data": {}})


app = web.Application()
app.router.add_post("/v1/test", index)

# init docs with all parameters, usual for ApiSpec
setup_aiohttp_apispec(
    app=app, 
    title="My Documentation", 
    version="v1",
    url="/api/docs/swagger.json",
    swagger_path="/api/docs",
)

# Now we can find spec on 'http://localhost:8080/api/docs/swagger.json'
# and docs on 'http://localhost:8080/api/docs'
web.run_app(app)
```
Class based views are also supported:
```python
class TheView(web.View):
    @docs(
        tags=["mytag"],
        summary="View method summary",
        description="View method description",
    )
    @request_schema(RequestSchema(strict=True))
    @response_schema(ResponseSchema(), 200)
    def delete(self):
        return web.json_response(
            {"msg": "done", "data": {"name": self.request["data"]["name"]}}
        )


app.router.add_view("/v1/view", TheView)
```

As alternative you can add responses info to `docs` decorator, which is more compact way. 
And it allows you not to use schemas for responses documentation:

```python
@docs(
    tags=["mytag"],
    summary="Test method summary",
    description="Test method description",
    responses={
        200: {
            "schema": ResponseSchema,
            "description": "Success response",
        },  # regular response
        404: {"description": "Not found"},  # responses without schema
        422: {"description": "Validation error"},
    },
)
@request_schema(RequestSchema(strict=True))
async def index(request):
    return web.json_response({"msg": "done", "data": {}})
```

## Adding validation middleware

```Python
from aiohttp_apispec import validation_middleware

...

app.middlewares.append(validation_middleware)
```
Now you can access all validated data in route from ```request['data']``` like so:

```Python
@docs(
    tags=["mytag"],
    summary="Test method summary",
    description="Test method description",
)
@request_schema(RequestSchema(strict=True))
@response_schema(ResponseSchema, 200)
async def index(request):
    uid = request["data"]["id"]
    name = request["data"]["name"]
    return web.json_response(
        {"msg": "done", "data": {"info": f"name - {name}, id - {uid}"}}
    )
```


You can change ``Request``'s ``'data'`` param to another with ``request_data_name`` argument of 
``setup_aiohttp_apispec`` function:

```python
setup_aiohttp_apispec(
    app=app,
    request_data_name="validated_data",
)

...


@request_schema(RequestSchema(strict=True))
async def index(request):
    uid = request["validated_data"]["id"]
    ...
```

Also you can do it for specific view using ```put_into``` 
parameter (beginning from version 2.0):

```python
@request_schema(RequestSchema(strict=True), put_into="validated_data")
async def index(request):
    uid = request["validated_data"]["id"]
    ...
```

## More decorators

Starting from version 2.0 you can use shortenings for documenting and validating 
specific request parts like cookies, headers etc using those decorators:

| Decorator name | Default put_into param |
|:----------|:-----------------|
| match_info_schema | match_info |
| querystring_schema | querystring |
| form_schema | form |
| json_schema | json |
| headers_schema | headers |
| cookies_schema | cookies | 

And example:

```python
@docs(
    tags=["users"],
    summary="Create new user",
    description="Add new user to our toy database",
    responses={
        200: {"description": "Ok. User created", "schema": OkResponse},
        401: {"description": "Unauthorized"},
        422: {"description": "Validation error"},
        500: {"description": "Server error"},
    },
)
@headers_schema(AuthHeaders)  # <- schema for headers validation
@json_schema(UserMeta)  # <- schema for json body validation
@querystring_schema(UserParams)  # <- schema for querystring params validation
async def create_user(request: web.Request):
    headers = request["headers"]  # <- validated headers!
    json_data = request["json"]  # <- validated json!
    query_params = request["querystring"]  # <- validated querystring!
    ...
```

## Custom error handling

If you want to catch validation errors by yourself you 
could use `error_callback` parameter and create your custom error handler. Note that
it can be one of coroutine or callable and it should 
have interface exactly like in examples below:

```python
from marshmallow import ValidationError, Schema
from aiohttp import web
from typing import Optional, Mapping, NoReturn


def my_error_handler(
    error: ValidationError,
    req: web.Request,
    schema: Schema,
    error_status_code: Optional[int] = None,
    error_headers: Optional[Mapping[str, str]] = None,
) -> NoReturn:
    raise web.HTTPBadRequest(
            body=json.dumps(error.messages),
            headers=error_headers,
            content_type="application/json",
        )

setup_aiohttp_apispec(app, error_callback=my_error_handler)
```
Also you can create your own exceptions and create 
regular Request in middleware like so:

```python
class MyException(Exception):
    def __init__(self, message):
        self.message = message

# It can be coroutine as well:
async def my_error_handler(
    error, req, schema, error_status_code, error_headers
):
    await req.app["db"].do_smth()  # So you can use some async stuff
    raise MyException({"errors": error.messages, "text": "Oops"})

# This middleware will handle your own exceptions:
@web.middleware
async def intercept_error(request, handler):
    try:
        return await handler(request)
    except MyException as e:
        return web.json_response(e.message, status=400)


setup_aiohttp_apispec(app, error_callback=my_error_handler)

# Do not forget to add your own middleware before validation_middleware
app.middlewares.extend([intercept_error, validation_middleware])
```

## Build swagger web client

#### 3.X SwaggerUI version

Just add `swagger_path` parameter to `setup_aiohttp_apispec` function.

For example:

```python
setup_aiohttp_apispec(app, swagger_path="/docs")
```

Then go to `/docs` and see awesome SwaggerUI

#### 2.X SwaggerUI version

If you prefer older version you can use 
[aiohttp_swagger](https://github.com/cr0hn/aiohttp-swagger) library.
`aiohttp-apispec` adds `swagger_dict` parameter to aiohttp web application 
after initialization (with `setup_aiohttp_apispec` function). 
So you can use it easily like:

```Python
from aiohttp_apispec import setup_aiohttp_apispec
from aiohttp_swagger import setup_swagger


def create_app(app):
    setup_aiohttp_apispec(app)

    async def swagger(app):
        setup_swagger(
            app=app, swagger_url="/api/doc", swagger_info=app["swagger_dict"]
        )

    app.on_startup.append(swagger)
    # now we can access swagger client on '/api/doc' url
    ...
    return app
```

## Versioning

This software follows [Semantic Versioning](http://semver.org/).

------

Please star this repository if this project helped you!



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/maximdanilchenko/aiohttp-apispec",
    "name": "aiohttp-apispec",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.5",
    "maintainer_email": "",
    "keywords": "aiohttp marshmallow apispec swagger",
    "author": "Danilchenko Maksim",
    "author_email": "dmax.dev@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/4a/47/72e2a08bb9990264cd058d1fef90b7378b459ad5d530aabcf10fe837d8e2/aiohttp-apispec-2.2.3.tar.gz",
    "platform": "",
    "description": "<h1 align=\"center\">aiohttp-apispec</h1>\n<p align=\"center\">Build and document REST APIs with <a href=\"https://github.com/aio-libs/aiohttp\">aiohttp</a> and <a href=\"https://github.com/marshmallow-code/apispec\">apispec</a></p>\n\n<p align=\"center\">\n  <a href=\"https://pypi.python.org/pypi/aiohttp-apispec\"><img src=\"https://badge.fury.io/py/aiohttp-apispec.svg\" alt=\"Pypi\"></a>\n  <a href=\"https://github.com/maximdanilchenko/aiohttp-apispec/graphs/contributors\"><img src=\"https://img.shields.io/github/contributors/maximdanilchenko/aiohttp-apispec.svg\" alt=\"Contributors\"></a>\n  <a href=\"https://pepy.tech/project/aiohttp-apispec\"><img src=\"https://pepy.tech/badge/aiohttp-apispec\" alt=\"Downloads\"></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://travis-ci.org/maximdanilchenko/aiohttp-apispec\"><img src=\"https://travis-ci.org/maximdanilchenko/aiohttp-apispec.svg\" alt=\"build status\"></a>\n  <a href=\"https://aiohttp-apispec.readthedocs.io/en/latest/?badge=latest\"><img src=\"https://readthedocs.org/projects/aiohttp-apispec/badge/?version=latest\" alt=\"[docs]\"></a>\n  <a href=\"https://codecov.io/gh/maximdanilchenko/aiohttp-apispec\"><img src=\"https://codecov.io/gh/maximdanilchenko/aiohttp-apispec/branch/master/graph/badge.svg\" alt=\"[codcov]\"></a>\n  <a href=\"https://github.com/ambv/black\"><img src=\"https://img.shields.io/badge/code%20style-black-000000.svg\" alt=\"Code style: black\"></a>\n</p>\n\n<p>\n\n```aiohttp-apispec``` key features:\n- ```docs``` and ```request_schema``` decorators \nto add swagger spec support out of the box;\n- ```validation_middleware``` middleware to enable validating \nwith marshmallow schemas from those decorators;\n- **SwaggerUI** support.\n- *New from version 2.0* -  ```match_info_schema```, ```querystring_schema```, \n```form_schema```, ```json_schema```, ```headers_schema``` and ```cookies_schema``` \ndecorators for specific request parts validation. \nLook [here](#more-decorators) for more info.\n\n```aiohttp-apispec``` api is fully inspired by ```flask-apispec``` library\n\n## Contents\n\n- [Install](#install)\n- [Quickstart](#quickstart)\n- [Adding validation middleware](#adding-validation-middleware)\n- [More decorators](#more-decorators)\n- [Custom error handling](#custom-error-handling)\n- [Build swagger web client](#build-swagger-web-client)\n- [Versioning](#versioning)\n\n\n## Install\n\n```\npip install aiohttp-apispec\n```\n\n## Quickstart\n\n*Also you can read [blog post](https://dmax.blog/how_to_easily_build_modern_web_apis_with_python_and_aiohttp) about quickstart with aiohttp-apispec*\n\n```Python\nfrom aiohttp_apispec import (\n    docs,\n    request_schema,\n    setup_aiohttp_apispec,\n)\nfrom aiohttp import web\nfrom marshmallow import Schema, fields\n\n\nclass RequestSchema(Schema):\n    id = fields.Int()\n    name = fields.Str(description=\"name\")\n\n@docs(\n    tags=[\"mytag\"],\n    summary=\"Test method summary\",\n    description=\"Test method description\",\n)\n@request_schema(RequestSchema(strict=True))\nasync def index(request):\n    return web.json_response({\"msg\": \"done\", \"data\": {}})\n\n\napp = web.Application()\napp.router.add_post(\"/v1/test\", index)\n\n# init docs with all parameters, usual for ApiSpec\nsetup_aiohttp_apispec(\n    app=app, \n    title=\"My Documentation\", \n    version=\"v1\",\n    url=\"/api/docs/swagger.json\",\n    swagger_path=\"/api/docs\",\n)\n\n# Now we can find spec on 'http://localhost:8080/api/docs/swagger.json'\n# and docs on 'http://localhost:8080/api/docs'\nweb.run_app(app)\n```\nClass based views are also supported:\n```python\nclass TheView(web.View):\n    @docs(\n        tags=[\"mytag\"],\n        summary=\"View method summary\",\n        description=\"View method description\",\n    )\n    @request_schema(RequestSchema(strict=True))\n    @response_schema(ResponseSchema(), 200)\n    def delete(self):\n        return web.json_response(\n            {\"msg\": \"done\", \"data\": {\"name\": self.request[\"data\"][\"name\"]}}\n        )\n\n\napp.router.add_view(\"/v1/view\", TheView)\n```\n\nAs alternative you can add responses info to `docs` decorator, which is more compact way. \nAnd it allows you not to use schemas for responses documentation:\n\n```python\n@docs(\n    tags=[\"mytag\"],\n    summary=\"Test method summary\",\n    description=\"Test method description\",\n    responses={\n        200: {\n            \"schema\": ResponseSchema,\n            \"description\": \"Success response\",\n        },  # regular response\n        404: {\"description\": \"Not found\"},  # responses without schema\n        422: {\"description\": \"Validation error\"},\n    },\n)\n@request_schema(RequestSchema(strict=True))\nasync def index(request):\n    return web.json_response({\"msg\": \"done\", \"data\": {}})\n```\n\n## Adding validation middleware\n\n```Python\nfrom aiohttp_apispec import validation_middleware\n\n...\n\napp.middlewares.append(validation_middleware)\n```\nNow you can access all validated data in route from ```request['data']``` like so:\n\n```Python\n@docs(\n    tags=[\"mytag\"],\n    summary=\"Test method summary\",\n    description=\"Test method description\",\n)\n@request_schema(RequestSchema(strict=True))\n@response_schema(ResponseSchema, 200)\nasync def index(request):\n    uid = request[\"data\"][\"id\"]\n    name = request[\"data\"][\"name\"]\n    return web.json_response(\n        {\"msg\": \"done\", \"data\": {\"info\": f\"name - {name}, id - {uid}\"}}\n    )\n```\n\n\nYou can change ``Request``'s ``'data'`` param to another with ``request_data_name`` argument of \n``setup_aiohttp_apispec`` function:\n\n```python\nsetup_aiohttp_apispec(\n    app=app,\n    request_data_name=\"validated_data\",\n)\n\n...\n\n\n@request_schema(RequestSchema(strict=True))\nasync def index(request):\n    uid = request[\"validated_data\"][\"id\"]\n    ...\n```\n\nAlso you can do it for specific view using ```put_into``` \nparameter (beginning from version 2.0):\n\n```python\n@request_schema(RequestSchema(strict=True), put_into=\"validated_data\")\nasync def index(request):\n    uid = request[\"validated_data\"][\"id\"]\n    ...\n```\n\n## More decorators\n\nStarting from version 2.0 you can use shortenings for documenting and validating \nspecific request parts like cookies, headers etc using those decorators:\n\n| Decorator name | Default put_into param |\n|:----------|:-----------------|\n| match_info_schema | match_info |\n| querystring_schema | querystring |\n| form_schema | form |\n| json_schema | json |\n| headers_schema | headers |\n| cookies_schema | cookies | \n\nAnd example:\n\n```python\n@docs(\n    tags=[\"users\"],\n    summary=\"Create new user\",\n    description=\"Add new user to our toy database\",\n    responses={\n        200: {\"description\": \"Ok. User created\", \"schema\": OkResponse},\n        401: {\"description\": \"Unauthorized\"},\n        422: {\"description\": \"Validation error\"},\n        500: {\"description\": \"Server error\"},\n    },\n)\n@headers_schema(AuthHeaders)  # <- schema for headers validation\n@json_schema(UserMeta)  # <- schema for json body validation\n@querystring_schema(UserParams)  # <- schema for querystring params validation\nasync def create_user(request: web.Request):\n    headers = request[\"headers\"]  # <- validated headers!\n    json_data = request[\"json\"]  # <- validated json!\n    query_params = request[\"querystring\"]  # <- validated querystring!\n    ...\n```\n\n## Custom error handling\n\nIf you want to catch validation errors by yourself you \ncould use `error_callback` parameter and create your custom error handler. Note that\nit can be one of coroutine or callable and it should \nhave interface exactly like in examples below:\n\n```python\nfrom marshmallow import ValidationError, Schema\nfrom aiohttp import web\nfrom typing import Optional, Mapping, NoReturn\n\n\ndef my_error_handler(\n    error: ValidationError,\n    req: web.Request,\n    schema: Schema,\n    error_status_code: Optional[int] = None,\n    error_headers: Optional[Mapping[str, str]] = None,\n) -> NoReturn:\n    raise web.HTTPBadRequest(\n            body=json.dumps(error.messages),\n            headers=error_headers,\n            content_type=\"application/json\",\n        )\n\nsetup_aiohttp_apispec(app, error_callback=my_error_handler)\n```\nAlso you can create your own exceptions and create \nregular Request in middleware like so:\n\n```python\nclass MyException(Exception):\n    def __init__(self, message):\n        self.message = message\n\n# It can be coroutine as well:\nasync def my_error_handler(\n    error, req, schema, error_status_code, error_headers\n):\n    await req.app[\"db\"].do_smth()  # So you can use some async stuff\n    raise MyException({\"errors\": error.messages, \"text\": \"Oops\"})\n\n# This middleware will handle your own exceptions:\n@web.middleware\nasync def intercept_error(request, handler):\n    try:\n        return await handler(request)\n    except MyException as e:\n        return web.json_response(e.message, status=400)\n\n\nsetup_aiohttp_apispec(app, error_callback=my_error_handler)\n\n# Do not forget to add your own middleware before validation_middleware\napp.middlewares.extend([intercept_error, validation_middleware])\n```\n\n## Build swagger web client\n\n#### 3.X SwaggerUI version\n\nJust add `swagger_path` parameter to `setup_aiohttp_apispec` function.\n\nFor example:\n\n```python\nsetup_aiohttp_apispec(app, swagger_path=\"/docs\")\n```\n\nThen go to `/docs` and see awesome SwaggerUI\n\n#### 2.X SwaggerUI version\n\nIf you prefer older version you can use \n[aiohttp_swagger](https://github.com/cr0hn/aiohttp-swagger) library.\n`aiohttp-apispec` adds `swagger_dict` parameter to aiohttp web application \nafter initialization (with `setup_aiohttp_apispec` function). \nSo you can use it easily like:\n\n```Python\nfrom aiohttp_apispec import setup_aiohttp_apispec\nfrom aiohttp_swagger import setup_swagger\n\n\ndef create_app(app):\n    setup_aiohttp_apispec(app)\n\n    async def swagger(app):\n        setup_swagger(\n            app=app, swagger_url=\"/api/doc\", swagger_info=app[\"swagger_dict\"]\n        )\n\n    app.on_startup.append(swagger)\n    # now we can access swagger client on '/api/doc' url\n    ...\n    return app\n```\n\n## Versioning\n\nThis software follows [Semantic Versioning](http://semver.org/).\n\n------\n\nPlease star this repository if this project helped you!\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Build and document REST APIs with aiohttp and apispec",
    "version": "2.2.3",
    "project_urls": {
        "Homepage": "https://github.com/maximdanilchenko/aiohttp-apispec"
    },
    "split_keywords": [
        "aiohttp",
        "marshmallow",
        "apispec",
        "swagger"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4a4772e2a08bb9990264cd058d1fef90b7378b459ad5d530aabcf10fe837d8e2",
                "md5": "2c7c46684f908b8bb53c557d8d053f23",
                "sha256": "d70431e5f3ef5c6dc96dc9180ce10ddfd78fa054f178af8259707eb6d421ed05"
            },
            "downloads": -1,
            "filename": "aiohttp-apispec-2.2.3.tar.gz",
            "has_sig": false,
            "md5_digest": "2c7c46684f908b8bb53c557d8d053f23",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.5",
            "size": 2653064,
            "upload_time": "2022-03-01T14:35:30",
            "upload_time_iso_8601": "2022-03-01T14:35:30.973499Z",
            "url": "https://files.pythonhosted.org/packages/4a/47/72e2a08bb9990264cd058d1fef90b7378b459ad5d530aabcf10fe837d8e2/aiohttp-apispec-2.2.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-03-01 14:35:30",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "maximdanilchenko",
    "github_project": "aiohttp-apispec",
    "travis_ci": true,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "aiohttp",
            "specs": [
                [
                    "<",
                    "4.0"
                ],
                [
                    ">=",
                    "3.0.1"
                ]
            ]
        },
        {
            "name": "apispec",
            "specs": [
                [
                    ">=",
                    "5.1.1"
                ]
            ]
        },
        {
            "name": "webargs",
            "specs": [
                [
                    ">=",
                    "8.0.1"
                ]
            ]
        },
        {
            "name": "jinja2",
            "specs": []
        }
    ],
    "lcname": "aiohttp-apispec"
}
        
Elapsed time: 3.35583s