# apispec-aiohttp

[](https://codecov.io/github/kulapard/apispec-aiohttp)
[](https://results.pre-commit.ci/latest/github/kulapard/apispec-aiohttp/master)
[](https://pypi.org/project/apispec-aiohttp)
<br>
[](https://pepy.tech/projects/apispec-aiohttp)

[](https://github.com/kulapard/apispec-aiohttp/blob/master/LICENSE)
---
API documentation and validation for [aiohttp](https://github.com/aio-libs/aiohttp) using [apispec](https://github.com/marshmallow-code/apispec)
**apispec-aiohttp** key features:
- `docs` and `request_schema` decorators to add Swagger/OpenAPI spec support out of the box
- Specialized request part decorators: `match_info_schema`, `querystring_schema`, `form_schema`, `json_schema`, `headers_schema` and `cookies_schema` for targeted validation. See [Request Part Decorators](#more-decorators) for details.
- `validation_middleware` middleware to enable validating with marshmallow schemas
- Built-in [Swagger UI](https://github.com/swagger-api/swagger-ui) (`v5.20.1`)
**apispec-aiohttp** API is based on `aiohttp-apispec` (no longer maintained) which was inspired by the `flask-apispec` library
## Contents
- [Install](#install)
- [Example Application](#example-application)
- [Quickstart](#quickstart)
- [Adding validation middleware](#adding-validation-middleware)
- [More decorators](#more-decorators)
- [Custom error handling](#custom-error-handling)
- [SwaggerUI Integration](#swaggerui-integration)
- [Updating Swagger UI](#updating-swagger-ui)
## Install
With [uv](https://docs.astral.sh/uv/) package manager:
```bash
uv add apispec-aiohttp
```
or with pip:
```bash
pip install apispec-aiohttp
```
**Requirements:**
- Python 3.10+
- aiohttp 3.10+
- apispec 5.0+
- webargs 8.0+
- marshmallow 3.0+
## Example Application
A fully functional example application is included in the `example/` directory. This example demonstrates all the features of the library including:
- Request and response validation
- Swagger UI integration
- Different schema decorators
- Error handling
To run the example application:
```bash
make run-example
```
The example will be available at http://localhost:8080 with SwaggerUI at http://localhost:8080/api/docs.
## Quickstart
```python
from apispec_aiohttp import (
docs,
request_schema,
response_schema,
setup_apispec_aiohttp,
)
from aiohttp import web
from marshmallow import Schema, fields
class RequestSchema(Schema):
id = fields.Int()
name = fields.Str(description="name")
class ResponseSchema(Schema):
msg = fields.Str()
data = fields.Dict()
@docs(
tags=["mytag"],
summary="Test method summary",
description="Test method description",
)
@request_schema(RequestSchema())
@response_schema(ResponseSchema(), 200)
async def index(request):
# Access validated data from request
# data = request["data"]
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_apispec_aiohttp(
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
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())
@response_schema(ResponseSchema(), 200)
async def delete(self):
return web.json_response(
{"msg": "done", "data": {"name": self.request["data"]["name"]}}
)
app.router.add_view("/v1/view", TheView)
```
### Combining Documentation and Schemas
As an alternative, you can add responses info directly to the `docs` decorator, which is a more compact approach.
This method allows you to document responses without separate decorators:
```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())
async def index(request):
return web.json_response({"msg": "done", "data": {}})
```
## Adding validation middleware
```Python
from apispec_aiohttp 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_apispec_aiohttp`` function:
```python
setup_apispec_aiohttp(
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
You can use specialized decorators for documenting and validating specific parts of a request
such as cookies, headers, and more with these shorthand 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 |
### Example Usage of Specialized Schema Decorators:
```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_apispec_aiohttp(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_apispec_aiohttp(app, error_callback=my_error_handler)
# Do not forget to add your own middleware before validation_middleware
app.middlewares.extend([intercept_error, validation_middleware])
```
## SwaggerUI Integration
Just add `swagger_path` parameter to `setup_apispec_aiohttp` function.
For example:
```python
setup_apispec_aiohttp(app, swagger_path="/docs")
```
Then go to `/docs` to see the SwaggerUI.
## Updating Swagger UI
This package includes a built-in Swagger UI distribution. The Swagger UI version is automatically checked weekly by a GitHub Action, which creates a pull request when a new version is available.
### Manual Updates
To manually update Swagger UI to the latest version:
```bash
make update-swagger-ui
```
This command will:
1. Check the current version of Swagger UI in the project
2. Fetch the latest version from the [Swagger UI GitHub repository](https://github.com/swagger-api/swagger-ui)
3. If a newer version is available, it will download and update the UI files
4. Run pre-commit hooks to ensure the code quality
You can also update the Swagger UI by directly running:
```bash
python tools/update_swagger_ui.py
```
The script automatically handles all the necessary modifications to make Swagger UI work within the package.
### Automated Updates
The project has a GitHub workflow (`check-swagger-ui.yml`) that runs weekly to check for new Swagger UI versions. When a new version is detected, the workflow:
1. Creates a new branch
2. Updates the Swagger UI files
3. Creates a pull request with the changes
This ensures the project stays up-to-date with the latest Swagger UI version without manual intervention.
## Versioning
This library uses semantic versioning:
- Major version changes indicate breaking API changes
- Minor version changes add new features in a backward-compatible manner
- Patch version changes fix bugs in a backward-compatible manner
Version history is available in the [GitHub releases](https://github.com/kulapard/apispec-aiohttp/releases) page.
## Support
If you encounter any issues or have suggestions for improvements, please open an issue in this GitHub repository.
Please star this repository if this project helped you!
## License
This project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "apispec-aiohttp",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "aiohttp, apispec, marshmallow, swagger",
"author": null,
"author_email": "Taras Drapalyuk <taras@drapalyuk.com>",
"download_url": "https://files.pythonhosted.org/packages/e4/5a/b0b0f2caddf786cad153e1981fd0b9fa3a4987608013cd409610a69cf377/apispec_aiohttp-0.4.2.tar.gz",
"platform": null,
"description": "# apispec-aiohttp\n\n\n[](https://codecov.io/github/kulapard/apispec-aiohttp)\n[](https://results.pre-commit.ci/latest/github/kulapard/apispec-aiohttp/master)\n[](https://pypi.org/project/apispec-aiohttp)\n<br>\n[](https://pepy.tech/projects/apispec-aiohttp)\n\n[](https://github.com/kulapard/apispec-aiohttp/blob/master/LICENSE)\n---\n\nAPI documentation and validation for [aiohttp](https://github.com/aio-libs/aiohttp) using [apispec](https://github.com/marshmallow-code/apispec)\n\n**apispec-aiohttp** key features:\n- `docs` and `request_schema` decorators to add Swagger/OpenAPI spec support out of the box\n- Specialized request part decorators: `match_info_schema`, `querystring_schema`, `form_schema`, `json_schema`, `headers_schema` and `cookies_schema` for targeted validation. See [Request Part Decorators](#more-decorators) for details.\n- `validation_middleware` middleware to enable validating with marshmallow schemas\n- Built-in [Swagger UI](https://github.com/swagger-api/swagger-ui) (`v5.20.1`)\n\n**apispec-aiohttp** API is based on `aiohttp-apispec` (no longer maintained) which was inspired by the `flask-apispec` library\n\n\n## Contents\n\n- [Install](#install)\n- [Example Application](#example-application)\n- [Quickstart](#quickstart)\n- [Adding validation middleware](#adding-validation-middleware)\n- [More decorators](#more-decorators)\n- [Custom error handling](#custom-error-handling)\n- [SwaggerUI Integration](#swaggerui-integration)\n- [Updating Swagger UI](#updating-swagger-ui)\n\n\n## Install\nWith [uv](https://docs.astral.sh/uv/) package manager:\n```bash\nuv add apispec-aiohttp\n```\nor with pip:\n```bash\npip install apispec-aiohttp\n```\n\n**Requirements:**\n- Python 3.10+\n- aiohttp 3.10+\n- apispec 5.0+\n- webargs 8.0+\n- marshmallow 3.0+\n\n## Example Application\n\nA fully functional example application is included in the `example/` directory. This example demonstrates all the features of the library including:\n\n- Request and response validation\n- Swagger UI integration\n- Different schema decorators\n- Error handling\n\nTo run the example application:\n\n```bash\nmake run-example\n```\n\nThe example will be available at http://localhost:8080 with SwaggerUI at http://localhost:8080/api/docs.\n\n## Quickstart\n\n```python\nfrom apispec_aiohttp import (\n docs,\n request_schema,\n response_schema,\n setup_apispec_aiohttp,\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\nclass ResponseSchema(Schema):\n msg = fields.Str()\n data = fields.Dict()\n\n\n@docs(\n tags=[\"mytag\"],\n summary=\"Test method summary\",\n description=\"Test method description\",\n)\n@request_schema(RequestSchema())\n@response_schema(ResponseSchema(), 200)\nasync def index(request):\n # Access validated data from request\n # data = request[\"data\"]\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_apispec_aiohttp(\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```\n\n### Class Based Views\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())\n @response_schema(ResponseSchema(), 200)\n async 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\n### Combining Documentation and Schemas\n\nAs an alternative, you can add responses info directly to the `docs` decorator, which is a more compact approach.\nThis method allows you to document responses without separate decorators:\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())\nasync def index(request):\n return web.json_response({\"msg\": \"done\", \"data\": {}})\n```\n\n## Adding validation middleware\n\n```Python\nfrom apispec_aiohttp 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_apispec_aiohttp`` function:\n\n```python\nsetup_apispec_aiohttp(\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\nYou can use specialized decorators for documenting and validating specific parts of a request\nsuch as cookies, headers, and more with these shorthand 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\n### Example Usage of Specialized Schema Decorators:\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_apispec_aiohttp(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_apispec_aiohttp(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## SwaggerUI Integration\n\nJust add `swagger_path` parameter to `setup_apispec_aiohttp` function.\n\nFor example:\n\n```python\nsetup_apispec_aiohttp(app, swagger_path=\"/docs\")\n```\n\nThen go to `/docs` to see the SwaggerUI.\n\n## Updating Swagger UI\n\nThis package includes a built-in Swagger UI distribution. The Swagger UI version is automatically checked weekly by a GitHub Action, which creates a pull request when a new version is available.\n\n### Manual Updates\n\nTo manually update Swagger UI to the latest version:\n\n```bash\nmake update-swagger-ui\n```\n\nThis command will:\n1. Check the current version of Swagger UI in the project\n2. Fetch the latest version from the [Swagger UI GitHub repository](https://github.com/swagger-api/swagger-ui)\n3. If a newer version is available, it will download and update the UI files\n4. Run pre-commit hooks to ensure the code quality\n\nYou can also update the Swagger UI by directly running:\n\n```bash\npython tools/update_swagger_ui.py\n```\n\nThe script automatically handles all the necessary modifications to make Swagger UI work within the package.\n\n### Automated Updates\n\nThe project has a GitHub workflow (`check-swagger-ui.yml`) that runs weekly to check for new Swagger UI versions. When a new version is detected, the workflow:\n\n1. Creates a new branch\n2. Updates the Swagger UI files\n3. Creates a pull request with the changes\n\nThis ensures the project stays up-to-date with the latest Swagger UI version without manual intervention.\n\n## Versioning\n\nThis library uses semantic versioning:\n- Major version changes indicate breaking API changes\n- Minor version changes add new features in a backward-compatible manner\n- Patch version changes fix bugs in a backward-compatible manner\n\nVersion history is available in the [GitHub releases](https://github.com/kulapard/apispec-aiohttp/releases) page.\n\n## Support\n\nIf you encounter any issues or have suggestions for improvements, please open an issue in this GitHub repository.\nPlease star this repository if this project helped you!\n\n## License\n\nThis project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "API documentation and validation for aiohttp using apispec",
"version": "0.4.2",
"project_urls": {
"Homepage": "https://github.com/kulapard/apispec-aiohttp",
"Issues": "https://github.com/kulapard/apispec-aiohttp/issues"
},
"split_keywords": [
"aiohttp",
" apispec",
" marshmallow",
" swagger"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "38ee002d75f2081a6e23bc9c1b9a715ceb2825ecfb97a4c7140c22008a1b49ea",
"md5": "bfc7ac6b1ff2fd1d9569dbdebfb186d7",
"sha256": "a3a260d01c62f9890177c03dbdd1dea8fae19099e801c56433e89c2bd1bdee51"
},
"downloads": -1,
"filename": "apispec_aiohttp-0.4.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "bfc7ac6b1ff2fd1d9569dbdebfb186d7",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 3185282,
"upload_time": "2025-03-21T21:39:03",
"upload_time_iso_8601": "2025-03-21T21:39:03.692043Z",
"url": "https://files.pythonhosted.org/packages/38/ee/002d75f2081a6e23bc9c1b9a715ceb2825ecfb97a4c7140c22008a1b49ea/apispec_aiohttp-0.4.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "e45ab0b0f2caddf786cad153e1981fd0b9fa3a4987608013cd409610a69cf377",
"md5": "abd643149132a001e0867835619ea028",
"sha256": "c8a26e8603ca9f396eca745db9d7d4d141c8fe7e0fed0f16744a89c5725630c8"
},
"downloads": -1,
"filename": "apispec_aiohttp-0.4.2.tar.gz",
"has_sig": false,
"md5_digest": "abd643149132a001e0867835619ea028",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 3160728,
"upload_time": "2025-03-21T21:39:05",
"upload_time_iso_8601": "2025-03-21T21:39:05.749271Z",
"url": "https://files.pythonhosted.org/packages/e4/5a/b0b0f2caddf786cad153e1981fd0b9fa3a4987608013cd409610a69cf377/apispec_aiohttp-0.4.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-03-21 21:39:05",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "kulapard",
"github_project": "apispec-aiohttp",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "apispec-aiohttp"
}