Package: aiohttp-apispec-patch
aiohttp-apispecBuild and document REST APIs withaiohttpandapispecaiohttp-apispeckey features:docsandrequest_schemadecorators
to add swagger spec support out of the box;validation_middlewaremiddleware to enable validating
with marshmallow schemas from those decorators;SwaggerUIsupport.New from version 2.0-match_info_schema,querystring_schema,form_schema,json_schema,headers_schemaandcookies_schemadecorators for specific request parts validation.
Lookherefor more info.aiohttp-apispecapi is fully inspired byflask-apispeclibraryContentsInstallQuickstartAdding validation middlewareMore decoratorsCustom error handlingBuild swagger web clientInstallpip install aiohttp-apispecQuickstartfromaiohttp_apispecimport(docs,request_schema,setup_aiohttp_apispec,)fromaiohttpimportwebfrommarshmallowimportSchema,fieldsclassRequestSchema(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))asyncdefindex(request):returnweb.json_response({"msg":"done","data":{}})app=web.Application()app.router.add_post("/v1/test",index)# init docs with all parameters, usual for ApiSpecsetup_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:classTheView(web.View):@docs(tags=["mytag"],summary="View method summary",description="View method description",)@request_schema(RequestSchema(strict=True))@response_schema(ResponseSchema(),200)defdelete(self):returnweb.json_response({"msg":"done","data":{"name":self.request["data"]["name"]}})app.router.add_view("/v1/view",TheView)As alternative you can add responses info todocsdecorator, which is more compact way.
And it allows you not to use schemas for responses documentation:@docs(tags=["mytag"],summary="Test method summary",description="Test method description",responses={200:{"schema":ResponseSchema,"description":"Success response",},# regular response404:{"description":"Not found"},# responses without schema422:{"description":"Validation error"},},)@request_schema(RequestSchema(strict=True))asyncdefindex(request):returnweb.json_response({"msg":"done","data":{}})Adding validation middlewarefromaiohttp_apispecimportvalidation_middleware...app.middlewares.append(validation_middleware)Now you can access all validated data in route fromrequest['data']like so:@docs(tags=["mytag"],summary="Test method summary",description="Test method description",)@request_schema(RequestSchema(strict=True))@response_schema(ResponseSchema,200)asyncdefindex(request):uid=request["data"]["id"]name=request["data"]["name"]returnweb.json_response({"msg":"done","data":{"info":f"name -{name}, id -{uid}"}})You can changeRequest's'data'param to another withrequest_data_nameargument ofsetup_aiohttp_apispecfunction:setup_aiohttp_apispec(app=app,request_data_name="validated_data",)...@request_schema(RequestSchema(strict=True))asyncdefindex(request):uid=request["validated_data"]["id"]...Also you can do it for specific view usingput_intoparameter (beginning from version 2.0):@request_schema(RequestSchema(strict=True),put_into="validated_data")asyncdefindex(request):uid=request["validated_data"]["id"]...More decoratorsStarting from version 2.0 you can use shortenings for documenting and validating
specific request parts like cookies, headers etc using those decorators:Decorator nameDefault put_into parammatch_info_schemamatch_infoquerystring_schemaquerystringform_schemaformjson_schemajsonheaders_schemaheaderscookies_schemacookiesAnd example:@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 validationasyncdefcreate_user(request:web.Request):headers=request["headers"]# <- validated headers!json_data=request["json"]# <- validated json!query_params=request["querystring"]# <- validated querystring!...Custom error handlingIf you want to catch validation errors by yourself you
could useerror_callbackparameter 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:frommarshmallowimportValidationError,SchemafromaiohttpimportwebfromtypingimportOptional,Mapping,NoReturndefmy_error_handler(error:ValidationError,req:web.Request,schema:Schema,error_status_code:Optional[int]=None,error_headers:Optional[Mapping[str,str]]=None,)->NoReturn:raiseweb.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:classMyException(Exception):def__init__(self,message):self.message=message# It can be coroutine as well:asyncdefmy_error_handler(error,req,schema,error_status_code,error_headers):awaitreq.app["db"].do_smth()# So you can use some async stuffraiseMyException({"errors":error.messages,"text":"Oops"})# This middleware will handle your own exceptions:@web.middlewareasyncdefintercept_error(request,handler):try:returnawaithandler(request)exceptMyExceptionase:returnweb.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_middlewareapp.middlewares.extend([intercept_error,validation_middleware])Build swagger web client3.X SwaggerUI versionJust addswagger_pathparameter tosetup_aiohttp_apispecfunction.For example:setup_aiohttp_apispec(app,swagger_path="/docs")Then go to/docsand see awesome SwaggerUI2.X SwaggerUI versionIf you prefer older version you can useaiohttp_swaggerlibrary.aiohttp-apispecaddsswagger_dictparameter to aiohttp web application
after initialization (withsetup_aiohttp_apispecfunction).
So you can use it easily like:fromaiohttp_apispecimportsetup_aiohttp_apispecfromaiohttp_swaggerimportsetup_swaggerdefcreate_app(app):setup_aiohttp_apispec(app)asyncdefswagger(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...returnappPlease star this repository if this project helped you!