python-aiohttp-apispec_3.0.0~b2+ds1.orig/LICENSE0000644000000000000000000000206314231014705016202 0ustar00MIT License Copyright (c) 2017 Maksim Danilchenko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. python-aiohttp-apispec_3.0.0~b2+ds1.orig/MANIFEST.in0000644000000000000000000000046714231014705016741 0ustar00include LICENSE include README.md include requirements.txt recursive-include aiohttp_apispec/static * graft aiohttp_apispec graft docs global-exclude *.pyc global-exclude *.pyd global-exclude *.so global-exclude *.lib global-exclude *.dll global-exclude *.a global-exclude *.obj prune docs/_build prune example python-aiohttp-apispec_3.0.0~b2+ds1.orig/PKG-INFO0000644000000000000000000002512714231014705016300 0ustar00Metadata-Version: 2.1 Name: aiohttp-apispec Version: 3.0.0b2 Summary: Build and document REST APIs with aiohttp and apispec Home-page: https://github.com/maximdanilchenko/aiohttp-apispec Author: Danilchenko Maksim Author-email: dmax.dev@gmail.com License: MIT Keywords: aiohttp marshmallow apispec swagger Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Requires-Python: >=3.6 Description-Content-Type: text/markdown License-File: LICENSE

aiohttp-apispec

Build and document REST APIs with aiohttp and apispec

Pypi Contributors Downloads

build status [docs] [codcov] Code style: black

```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 **Version 3.0.0b1 with apispec>=5.0 webargs>=8.0 is in beta now** (`pip install aiohttp-apispec==3.0.0b1`). ## 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! python-aiohttp-apispec_3.0.0~b2+ds1.orig/README.md0000644000000000000000000002354614231014705016465 0ustar00

aiohttp-apispec

Build and document REST APIs with aiohttp and apispec

Pypi Contributors Downloads

build status [docs] [codcov] Code style: black

```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 **Version 3.0.0b1 with apispec>=5.0 webargs>=8.0 is in beta now** (`pip install aiohttp-apispec==3.0.0b1`). ## 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! python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec.egg-info/0000755000000000000000000000000014231014705022042 5ustar00python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/0000755000000000000000000000000014231014705020350 5ustar00python-aiohttp-apispec_3.0.0~b2+ds1.orig/docs/0000755000000000000000000000000014231014705016124 5ustar00python-aiohttp-apispec_3.0.0~b2+ds1.orig/pyproject.toml0000644000000000000000000000020214231014705020102 0ustar00[tool.black] include = '\.py$' skip-string-normalization = true exclude = ''' ( migrations/ | protobuffers/ | venv/ ) ''' python-aiohttp-apispec_3.0.0~b2+ds1.orig/requirements.txt0000644000000000000000000000007114231014705020456 0ustar00aiohttp>=3.0.1,<4.0 apispec>=5.1.1 webargs>=8.0.1 jinja2 python-aiohttp-apispec_3.0.0~b2+ds1.orig/setup.cfg0000644000000000000000000000004614231014705017015 0ustar00[egg_info] tag_build = tag_date = 0 python-aiohttp-apispec_3.0.0~b2+ds1.orig/setup.py0000644000000000000000000000230214231014705016703 0ustar00from setuptools import find_packages, setup def read(file_name): with open(file_name, encoding="utf-8") as fp: content = fp.read() return content setup( name='aiohttp-apispec', version='3.0.0b2', description='Build and document REST APIs with aiohttp and apispec', long_description=read('README.md'), long_description_content_type="text/markdown", author='Danilchenko Maksim', author_email='dmax.dev@gmail.com', packages=find_packages(exclude=('test*',)), package_dir={'aiohttp_apispec': 'aiohttp_apispec'}, include_package_data=True, install_requires=read('requirements.txt').split(), license='MIT', url='https://github.com/maximdanilchenko/aiohttp-apispec', zip_safe=False, keywords='aiohttp marshmallow apispec swagger', python_requires='>=3.6', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', ], test_suite='tests', ) python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec.egg-info/PKG-INFO0000644000000000000000000002512714231014705023146 0ustar00Metadata-Version: 2.1 Name: aiohttp-apispec Version: 3.0.0b2 Summary: Build and document REST APIs with aiohttp and apispec Home-page: https://github.com/maximdanilchenko/aiohttp-apispec Author: Danilchenko Maksim Author-email: dmax.dev@gmail.com License: MIT Keywords: aiohttp marshmallow apispec swagger Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Requires-Python: >=3.6 Description-Content-Type: text/markdown License-File: LICENSE

aiohttp-apispec

Build and document REST APIs with aiohttp and apispec

Pypi Contributors Downloads

build status [docs] [codcov] Code style: black

```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 **Version 3.0.0b1 with apispec>=5.0 webargs>=8.0 is in beta now** (`pip install aiohttp-apispec==3.0.0b1`). ## 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! python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec.egg-info/SOURCES.txt0000644000000000000000000000222114231014705023723 0ustar00LICENSE MANIFEST.in README.md pyproject.toml requirements.txt setup.py aiohttp_apispec/__init__.py aiohttp_apispec/aiohttp_apispec.py aiohttp_apispec/middlewares.py aiohttp_apispec/utils.py aiohttp_apispec.egg-info/PKG-INFO aiohttp_apispec.egg-info/SOURCES.txt aiohttp_apispec.egg-info/dependency_links.txt aiohttp_apispec.egg-info/not-zip-safe aiohttp_apispec.egg-info/requires.txt aiohttp_apispec.egg-info/top_level.txt aiohttp_apispec/decorators/__init__.py aiohttp_apispec/decorators/docs.py aiohttp_apispec/decorators/request.py aiohttp_apispec/decorators/response.py aiohttp_apispec/static/favicon-16x16.png aiohttp_apispec/static/favicon-32x32.png aiohttp_apispec/static/index.html aiohttp_apispec/static/oauth2-redirect.html aiohttp_apispec/static/swagger-ui-bundle.js aiohttp_apispec/static/swagger-ui-bundle.js.map aiohttp_apispec/static/swagger-ui-standalone-preset.js aiohttp_apispec/static/swagger-ui-standalone-preset.js.map aiohttp_apispec/static/swagger-ui.css aiohttp_apispec/static/swagger-ui.css.map aiohttp_apispec/static/swagger-ui.js aiohttp_apispec/static/swagger-ui.js.map docs/api.rst docs/conf.py docs/index.rst docs/install.rst docs/usage.rstpython-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec.egg-info/dependency_links.txt0000644000000000000000000000000114231014705026110 0ustar00 python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec.egg-info/not-zip-safe0000644000000000000000000000000114231014705024270 0ustar00 python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec.egg-info/requires.txt0000644000000000000000000000007114231014705024440 0ustar00aiohttp<4.0,>=3.0.1 apispec>=5.1.1 webargs>=8.0.1 jinja2 python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec.egg-info/top_level.txt0000644000000000000000000000003014231014705024565 0ustar00aiohttp_apispec example python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/__init__.py0000644000000000000000000000131514231014705022461 0ustar00from .aiohttp_apispec import AiohttpApiSpec, setup_aiohttp_apispec from .decorators import ( cookies_schema, docs, form_schema, headers_schema, json_schema, marshal_with, match_info_schema, querystring_schema, request_schema, response_schema, use_kwargs, ) from .middlewares import validation_middleware __all__ = [ # setup "AiohttpApiSpec", "setup_aiohttp_apispec", # decorators "docs", "request_schema", "match_info_schema", "querystring_schema", "form_schema", "json_schema", "headers_schema", "cookies_schema", "response_schema", "use_kwargs", "marshal_with", # middleware "validation_middleware", ] python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/aiohttp_apispec.py0000644000000000000000000002622314231014705024103 0ustar00import copy import os from pathlib import Path from typing import Awaitable, Callable from aiohttp import web from aiohttp.hdrs import METH_ALL, METH_ANY from apispec import APISpec from apispec.core import VALID_METHODS_OPENAPI_V2 from apispec.ext.marshmallow import MarshmallowPlugin, common from jinja2 import Template from webargs.aiohttpparser import parser from .utils import get_path, get_path_keys, issubclass_py37fix _AiohttpView = Callable[[web.Request], Awaitable[web.StreamResponse]] VALID_RESPONSE_FIELDS = {"description", "headers", "examples"} DEFAULT_RESPONSE_LOCATION = "json" NAME_SWAGGER_SPEC = "swagger.spec" NAME_SWAGGER_DOCS = "swagger.docs" NAME_SWAGGER_STATIC = "swagger.static" INDEX_PAGE = "index.html" def resolver(schema): schema_instance = common.resolve_schema_instance(schema) prefix = "Partial-" if schema_instance.partial else "" schema_cls = common.resolve_schema_cls(schema) name = prefix + schema_cls.__name__ if name.endswith("Schema"): return name[:-6] or name return name class AiohttpApiSpec: def __init__( self, url="/api/docs/swagger.json", app=None, request_data_name="data", swagger_path=None, static_path='/static/swagger', error_callback=None, in_place=False, prefix='', schema_name_resolver=resolver, **kwargs, ): self.plugin = MarshmallowPlugin(schema_name_resolver=schema_name_resolver) self.spec = APISpec(plugins=(self.plugin,), openapi_version="2.0", **kwargs) self.url = url self.swagger_path = swagger_path self.static_path = static_path self._registered = False self._request_data_name = request_data_name self.error_callback = error_callback self.prefix = prefix self._index_page = None if app is not None: self.register(app, in_place) def swagger_dict(self): """Returns swagger spec representation in JSON format""" return self.spec.to_dict() def register(self, app: web.Application, in_place: bool = False): """Creates spec based on registered app routes and registers needed view""" if self._registered is True: return None app["_apispec_request_data_name"] = self._request_data_name if self.error_callback: parser.error_callback = self.error_callback app["_apispec_parser"] = parser if in_place: self._register(app) else: async def doc_routes(app_): self._register(app_) app.on_startup.append(doc_routes) self._registered = True if self.url is not None: async def swagger_handler(request): return web.json_response(request.app["swagger_dict"]) route_url = self.url if not self.url.startswith("/"): route_url = "/{}".format(self.url) app.router.add_route( "GET", route_url, swagger_handler, name=NAME_SWAGGER_SPEC ) if self.swagger_path is not None: self._add_swagger_web_page(app, self.static_path, self.swagger_path) def _get_index_page(self, app, static_files, static_path): if self._index_page is not None: return self._index_page with open(str(static_files / INDEX_PAGE)) as swg_tmp: url = self.url if app is None else app.router[NAME_SWAGGER_SPEC].url_for() if app is not None: static_path = app.router[NAME_SWAGGER_STATIC].url_for( filename=INDEX_PAGE ) static_path = os.path.dirname(str(static_path)) self._index_page = Template(swg_tmp.read()).render( path=url, static=static_path ) return self._index_page def _add_swagger_web_page( self, app: web.Application, static_path: str, view_path: str ): static_files = Path(__file__).parent / "static" app.router.add_static(static_path, static_files, name=NAME_SWAGGER_STATIC) async def swagger_view(_): index_page = self._get_index_page(app, static_files, static_path) return web.Response(text=index_page, content_type="text/html") app.router.add_route("GET", view_path, swagger_view, name=NAME_SWAGGER_DOCS) def _register(self, app: web.Application): for route in app.router.routes(): if issubclass_py37fix(route.handler, web.View) and route.method == METH_ANY: for attr in dir(route.handler): if attr.upper() in METH_ALL: view = getattr(route.handler, attr) method = attr self._register_route(route, method, view) else: method = route.method.lower() view = route.handler self._register_route(route, method, view) app["swagger_dict"] = self.swagger_dict() def _register_route( self, route: web.AbstractRoute, method: str, view: _AiohttpView ): if not hasattr(view, "__apispec__"): return None url_path = get_path(route) if not url_path: return None self._update_paths(view.__apispec__, method, self.prefix + url_path) def _update_paths(self, data: dict, method: str, url_path: str): if method not in VALID_METHODS_OPENAPI_V2: return None for schema in data.pop("schemas", []): parameters = self.plugin.converter.schema2parameters( schema["schema"], location=schema["location"], **schema["options"] ) self._add_examples(schema["schema"], parameters, schema["example"]) data["parameters"].extend(parameters) existing = [p["name"] for p in data["parameters"] if p["in"] == "path"] data["parameters"].extend( {"in": "path", "name": path_key, "required": True, "type": "string"} for path_key in get_path_keys(url_path) if path_key not in existing ) if "responses" in data: responses = {} for code, actual_params in data["responses"].items(): if "schema" in actual_params: raw_parameters = self.plugin.converter.schema2parameters( actual_params["schema"], location=DEFAULT_RESPONSE_LOCATION, required=actual_params.get("required", False), )[0] updated_params = { k: v for k, v in raw_parameters.items() if k in VALID_RESPONSE_FIELDS } updated_params['schema'] = actual_params["schema"] for extra_info in ("description", "headers", "examples"): if extra_info in actual_params: updated_params[extra_info] = actual_params[extra_info] responses[code] = updated_params else: responses[code] = actual_params data["responses"] = responses operations = copy.deepcopy(data) self.spec.path(path=url_path, operations={method: operations}) def _add_examples(self, ref_schema, endpoint_schema, example): def add_to_endpoint_or_ref(): if add_to_refs: self.spec.components.schemas[name]["example"] = example else: endpoint_schema[0]['schema']['allOf'] = [ endpoint_schema[0]['schema'].pop('$ref') ] endpoint_schema[0]['schema']["example"] = example if not example: return schema_instance = common.resolve_schema_instance(ref_schema) name = self.plugin.converter.schema_name_resolver(schema_instance) add_to_refs = example.pop('add_to_refs') if self.spec.components.openapi_version.major < 3: if name and name in self.spec.components.schemas: add_to_endpoint_or_ref() else: add_to_endpoint_or_ref() def setup_aiohttp_apispec( app: web.Application, *, title: str = "API documentation", version: str = "0.0.1", url: str = "/api/docs/swagger.json", request_data_name: str = "data", swagger_path: str = None, static_path: str = '/static/swagger', error_callback=None, in_place: bool = False, prefix: str = '', schema_name_resolver: Callable = resolver, **kwargs, ) -> None: """ aiohttp-apispec extension. Usage: .. code-block:: 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') bool_field = fields.Bool() @docs(tags=['mytag'], summary='Test method summary', description='Test method description') @request_schema(RequestSchema) 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/api-docs') # now we can find it on 'http://localhost:8080/api/docs/api-docs' web.run_app(app) :param Application app: aiohttp web app :param str title: API title :param str version: API version :param str url: url for swagger spec in JSON format :param str request_data_name: name of the key in Request object where validated data will be placed by validation_middleware (``'data'`` by default) :param str swagger_path: experimental SwaggerUI support (starting from v1.1.0). By default it is None (disabled) :param str static_path: path for static files used by SwaggerUI (if it is enabled with ``swagger_path``) :param error_callback: custom error handler :param in_place: register all routes at the moment of calling this function instead of the moment of the on_startup signal. If True, be sure all routes are added to router :param prefix: prefix to add to all registered routes :param schema_name_resolver: custom schema_name_resolver for MarshmallowPlugin. :param kwargs: any apispec.APISpec kwargs :return: return instance of AiohttpApiSpec class :rtype: AiohttpApiSpec """ return AiohttpApiSpec( url, app, request_data_name, title=title, version=version, swagger_path=swagger_path, static_path=static_path, error_callback=error_callback, in_place=in_place, prefix=prefix, schema_name_resolver=schema_name_resolver, **kwargs, ) python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/decorators/0000755000000000000000000000000014231014705022515 5ustar00python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/middlewares.py0000644000000000000000000000270714231014705023230 0ustar00from aiohttp import web from .utils import issubclass_py37fix @web.middleware async def validation_middleware(request: web.Request, handler) -> web.Response: """ Validation middleware for aiohttp web app Usage: .. code-block:: python app.middlewares.append(validation_middleware) """ orig_handler = request.match_info.handler if not hasattr(orig_handler, "__schemas__"): if not issubclass_py37fix(orig_handler, web.View): return await handler(request) sub_handler = getattr(orig_handler, request.method.lower(), None) if sub_handler is None: return await handler(request) if not hasattr(sub_handler, "__schemas__"): return await handler(request) schemas = sub_handler.__schemas__ else: schemas = orig_handler.__schemas__ result = {} for schema in schemas: data = await request.app["_apispec_parser"].parse( schema["schema"], request, location=schema["location"], unknown=None, # Pass None to use the schema’s setting instead. ) if schema["put_into"]: request[schema["put_into"]] = data elif data: try: result.update(data) except (ValueError, TypeError): result = data break request[request.app["_apispec_request_data_name"]] = result return await handler(request) python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/static/0000755000000000000000000000000014231014705021637 5ustar00python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/utils.py0000644000000000000000000000057114231014705022065 0ustar00from string import Formatter def get_path(route): path_info = route.resource.get_info() return path_info.get("path") or path_info.get("formatter") def get_path_keys(path): return [i[1] for i in Formatter().parse(path) if i[1]] def issubclass_py37fix(cls, cls_info): try: return issubclass(cls, cls_info) except TypeError: return False python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/decorators/__init__.py0000644000000000000000000000040114231014705024621 0ustar00from .docs import docs from .request import ( cookies_schema, form_schema, headers_schema, json_schema, match_info_schema, querystring_schema, request_schema, use_kwargs, ) from .response import marshal_with, response_schema python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/decorators/docs.py0000644000000000000000000000237614231014705024027 0ustar00def docs(**kwargs): """ Annotate the decorated view function with the specified Swagger attributes. Usage: .. code-block:: python from aiohttp import web @docs(tags=['my_tag'], summary='Test method summary', description='Test method description', parameters=[{ 'in': 'header', 'name': 'X-Request-ID', 'schema': {'type': 'string', 'format': 'uuid'}, 'required': 'true' }] ) async def index(request): return web.json_response({'msg': 'done', 'data': {}}) """ def wrapper(func): if not kwargs.get("produces"): kwargs["produces"] = ["application/json"] if not hasattr(func, "__apispec__"): func.__apispec__ = {"schemas": [], "responses": {}, "parameters": []} func.__schemas__ = [] extra_parameters = kwargs.pop("parameters", []) extra_responses = kwargs.pop("responses", {}) func.__apispec__["parameters"].extend(extra_parameters) func.__apispec__["responses"].update(extra_responses) func.__apispec__.update(kwargs) return func return wrapper python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/decorators/request.py0000644000000000000000000000703414231014705024563 0ustar00import copy from functools import partial # locations supported by both openapi and webargs.aiohttpparser VALID_SCHEMA_LOCATIONS = ( "cookies", "files", "form", "headers", "json", "match_info", "path", "query", "querystring", ) def request_schema( schema, location="json", put_into=None, example=None, add_to_refs=False, **kwargs ): """ Add request info into the swagger spec and prepare injection keyword arguments from the specified webargs arguments into the decorated view function in request['data'] for validation_middleware validation middleware. Usage: .. code-block:: python from aiohttp import web from marshmallow import Schema, fields class RequestSchema(Schema): id = fields.Int() name = fields.Str(description='name') @request_schema(RequestSchema(strict=True)) async def index(request): # aiohttp_apispec_middleware should be used for it data = request['data'] return web.json_response({'name': data['name'], 'id': data['id']}) :param schema: :class:`Schema ` class or instance :param location: Default request locations to parse :param put_into: name of the key in Request object where validated data will be placed. If None (by default) default key will be used :param dict example: Adding example for current schema :param bool add_to_refs: Working only if example not None, if True, add example for ref schema. Otherwise add example to endpoint. Default False """ if location not in VALID_SCHEMA_LOCATIONS: raise ValueError(f"Invalid location argument: {location}") if callable(schema): schema = schema() options = {"required": kwargs.pop("required", False)} def wrapper(func): if not hasattr(func, "__apispec__"): func.__apispec__ = {"schemas": [], "responses": {}, "parameters": []} func.__schemas__ = [] _example = copy.copy(example) or {} if _example: _example['add_to_refs'] = add_to_refs func.__apispec__["schemas"].append( { "schema": schema, "location": location, "options": options, "example": _example, } ) # TODO: Remove this block? # "body" location was replaced by "json" location if location == "json" and any( func_schema["location"] == "json" for func_schema in func.__schemas__ ): raise RuntimeError("Multiple json locations are not allowed") func.__schemas__.append( {"schema": schema, "location": location, "put_into": put_into} ) return func return wrapper # For backward compatibility use_kwargs = request_schema # Decorators for specific request data validations (shortenings) match_info_schema = partial( request_schema, location="match_info", put_into="match_info" ) querystring_schema = partial( request_schema, location="querystring", put_into="querystring" ) form_schema = partial(request_schema, location="form", put_into="form") json_schema = partial(request_schema, location="json", put_into="json") headers_schema = partial(request_schema, location="headers", put_into="headers") cookies_schema = partial(request_schema, location="cookies", put_into="cookies") python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/decorators/response.py0000644000000000000000000000227114231014705024727 0ustar00def response_schema(schema, code=200, required=False, description=None): """ Add response info into the swagger spec Usage: .. code-block:: python from aiohttp import web from marshmallow import Schema, fields class ResponseSchema(Schema): msg = fields.Str() data = fields.Dict() @response_schema(ResponseSchema(), 200) async def index(request): return web.json_response({'msg': 'done', 'data': {}}) :param str description: response description :param bool required: :param schema: :class:`Schema ` class or instance :param int code: HTTP response code """ if callable(schema): schema = schema() def wrapper(func): if not hasattr(func, "__apispec__"): func.__apispec__ = {"schemas": [], "responses": {}, "parameters": []} func.__schemas__ = [] func.__apispec__["responses"]["%s" % code] = { "schema": schema, "required": required, "description": description or "", } return func return wrapper # For backward compatibility marshal_with = response_schema python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/static/favicon-16x16.png0000644000000000000000000000123114231014705024552 0ustar00PNG  IHDR(-S5PLTEb4a4^5[5W7U7R8Q8/^@.]@-ZA+WA3f>4f?9o=%NC$MC$OC&MB$KB#LB!IC$KB$LB$MB%MB$NC%NCAD?ECDCDDD EC"IC"IC#JB'SA$LC&PA"GB"HC)VA+Y?$MA%MB6F4D2G3D5F1B 1I+@$I3M33-,,-,..}.|.v0t0r1q1p1o2m1m1l2k2j2i3h3h3g3K9J:J:D;C<@y=>w=9n>8m>8n?6j?5h?3e?=E>E?E=ECEDD FD`%/;tRNSϿL1$  IDATx=.CQnRi"1sֻ[A5;uZN^k.IvL-[ƬwKP:Nac0Nih$7T} k I@Ч\T. Iq˯lOE"ACbmWlB˭p[E1(IK6pŕ#8ke6꟩J9IENDB`python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/static/favicon-32x32.png0000644000000000000000000000116414231014705024553 0ustar00PNG  IHDR DPLTE3D5F6F6F.:5F8E7FZ6~.C;w/_59o>n2?xi&K X9|T!CY-[ <%ă .0g|&ƌF{gIENDB`python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/static/index.html0000644000000000000000000000271114231014705023635 0ustar00 Swagger UI

python-aiohttp-apispec_3.0.0~b2+ds1.orig/aiohttp_apispec/static/oauth2-redirect.html0000644000000000000000000000504314231014705025530 0ustar00 Swagger UI: OAuth2 Redirect python-aiohttp-apispec_3.0.0~b2+ds1.orig/docs/api.rst0000644000000000000000000000012514231014705017425 0ustar00.. _api: API Reference ============= .. automodule:: aiohttp_apispec :members: python-aiohttp-apispec_3.0.0~b2+ds1.orig/docs/conf.py0000644000000000000000000000131014231014705017416 0ustar00import datetime as dt import os import sys sys.path.insert(0, os.path.abspath('..')) extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode'] project = 'aiohttp-apispec' author = 'Maksim Danilchenko' copyright = 'Maksim Danilchenko and contributors {0:%Y}'.format(dt.datetime.utcnow()) version = '0.3.2' source_suffix = '.rst' master_doc = 'index' pygments_style = 'default' html_theme = 'sphinx_rtd_theme' html_static_path = ['_static'] html_theme_options = { 'description': 'Build and document REST APIs with aiohttp and apispec', 'show_powered_by': False, 'display_version': True, } html_title = 'aiohttp-apispec Documentation' html_short_title = 'aiohttp-apispec' python-aiohttp-apispec_3.0.0~b2+ds1.orig/docs/index.rst0000644000000000000000000000206014231014705017763 0ustar00=============== aiohttp-apispec =============== .. image:: https://badge.fury.io/py/aiohttp-apispec.svg :target: https://pypi.python.org/pypi/aiohttp-apispec .. image:: https://travis-ci.org/maximdanilchenko/aiohttp-apispec.svg :target: https://travis-ci.org/maximdanilchenko/aiohttp-apispec .. image:: https://codecov.io/gh/maximdanilchenko/aiohttp-apispec/branch/master/graph/badge.svg :target: https://codecov.io/gh/maximdanilchenko/aiohttp-apispec Build and document REST APIs with aiohttp and apispec ``aiohttp-apispec`` key features: - ``docs``, ``request_schema``, ``match_info_schema``, ``querystring_schema``, ``form_schema``, ``json_schema``, ``headers_schema``, ``cookies_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. ``aiohttp-apispec`` api is fully inspired by ``flask-apispec`` library Guide ----- .. toctree:: :maxdepth: 2 :caption: Contents: usage install api python-aiohttp-apispec_3.0.0~b2+ds1.orig/docs/install.rst0000644000000000000000000000012214231014705020317 0ustar00.. _install: Installation ============ :: $ pip install -U aiohttp-apispec python-aiohttp-apispec_3.0.0~b2+ds1.orig/docs/usage.rst0000644000000000000000000001740514231014705017771 0ustar00.. _usage: Usage ===== Quickstart ---------- .. note:: Using strict=True need only for marshmallow < 3.0.0 .. code-block:: python from aiohttp_apispec import (docs, request_schema, response_schema, setup_aiohttp_apispec) from aiohttp import web from marshmallow import Schema, fields class RequestSchema(Schema): id = fields.Int() name = fields.Str(description='name') bool_field = fields.Bool() class ResponseSchema(Schema): msg = fields.Str() data = fields.Dict() @docs(tags=['mytag'], summary='Test method summary', description='Test method description') @request_schema(RequestSchema(strict=True)) @response_schema(ResponseSchema(), 200) async def index(request): return web.json_response({'msg': 'done', 'data': {}}) # Class based views are also supported: class TheView(web.View): @docs( tags=['mytag'], summary='View method summary', description='View method description', ) @request_schema(RequestSchema(strict=True)) def delete(self): return web.json_response({ 'msg': 'done', 'data': {'name': self.request['data']['name']}, }) app = web.Application() app.router.add_post('/v1/test', index) app.router.add_view('/v1/view', TheView) # init docs with all parameters, usual for ApiSpec setup_aiohttp_apispec(app=app, title="My Documentation", version="v1") # find it on 'http://localhost:8080/api/docs/api-docs' web.run_app(app) Adding validation middleware ---------------------------- .. code-block:: 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: .. code-block:: 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: .. code-block:: python setup_aiohttp_apispec(app=app, request_data_name='validated_data', title='My Documentation', version='v1', url='/api/docs/api-docs') ... @request_schema(RequestSchema(strict=True)) 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: .. code-block:: 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) @json_schema(UserMeta) @querystring_schema(UserParams) 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: .. code-block:: 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: .. code-block:: python class MyException(Exception): def __init__(self, message): self.message = message # It can be coroutine as well: async 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: 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]) Named routes ------------ Routes for the Swagger UI and to the swagger specification file `swagger.json` are registered as `named resources