maximdanilchenko/aiohttp-apispec

Example from `More Decorators` is not correctly setting attributes on the request object

sad-boy-uoa opened this issue · 1 comments

Hi there, I have the following code inspired by the documentation

from aiohttp_apispec import (docs,
                             setup_aiohttp_apispec,
                             querystring_schema,
                             headers_schema,
                             json_schema)
from aiohttp import web
from marshmallow import Schema, fields


class AuthHeaders(Schema):
    a = fields.String()


class UserMeta(Schema):
    a = fields.String()


class UserParams(Schema):
    a = fields.String()


class OkResponse(Schema):
    a = fields.String()


@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!
    return web.json_response({"headers": headers, "json_data": json_data, "query_params": query_params})

app = web.Application()

app.router.add_post('/v1/create_user', create_user)

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

# find it on 'http://localhost:8080/api/docs/api-docs'
web.run_app(app)

When sending a the following request:

curl -X POST "http://localhost:8080/v1/create_user" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"a\": \"string\"}"

I get the following exception raised

======== Running on http://0.0.0.0:8080 ========
(Press CTRL+C to quit)
Error handling request
Traceback (most recent call last):
  File "/Users/chris.herrmann/Code/Sportsflare/real-time/scratch/env/lib/python3.7/site-packages/aiohttp/web_protocol.py", line 418, in start                                                                                                               
    resp = await task
  File "/Users/chris.herrmann/Code/Sportsflare/real-time/scratch/env/lib/python3.7/site-packages/aiohttp/web_app.py", line 458, in _handle                                                                                                                  
    resp = await handler(request)
  File "api_with_apispec.py", line 41, in create_user
    headers = request["headers"]  # <- validated headers!
  File "/Users/chris.herrmann/Code/Sportsflare/real-time/scratch/env/lib/python3.7/site-packages/aiohttp/web_request.py", line 237, in __getitem__                                                                                                          
    return self._state[key]
KeyError: 'headers'

What am I doing wrong here?

I realise the issue is to include the validator middleware on the application itself. IMO this isn't clear from the docs, but technically works.

e.g.

from aiohttp_apispec import validation_middleware

...

app.middlewares.append(validation_middleware)