Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Two errors in Schema #92

Open
elsimqoz opened this issue May 11, 2020 · 3 comments
Open

Two errors in Schema #92

elsimqoz opened this issue May 11, 2020 · 3 comments

Comments

@elsimqoz
Copy link

Ubuntu 18.04
Python 3.8.0
aiohttp==3.6.2
aiohttp-apispec==2.2.1

https://github.com/maximdanilchenko/aiohttp-apispec/blob/master/docs/usage.rst

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': {}})
  1. Run it, get error
Traceback (most recent call last):
  ...
    @request_schema(RequestSchema(strict=True))
TypeError: __init__() got an unexpected keyword argument 'strict'
  1. Let's add not-in-schema field
@response_schema(ResponseSchema(), 200)
return web.json_response({'msg': 'done',
                          'data': {}, 'foo': 'bar'})

It seems that ResponseSchema didn't validate response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Python/3.8 aiohttp/3.6.2

{
    "data": {},
    "foo": "bar",
    "msg": "done"
}

But directly it will

>>> ResponseSchema().validate({'msg': 'done', 'data': {}, 'foo': 'bar'})
{'foo': ['Unknown field.']}
@maximdanilchenko
Copy link
Owner

@elsimqoz
did you add validation middlware to your app?

@elsimqoz
Copy link
Author

elsimqoz commented Jul 2, 2020

@maximdanilchenko
yes

from aiohttp_apispec import setup_aiohttp_apispec, validation_middleware

app = Application(
    ...
    middlewares=[error_middleware, validation_middleware],
)

setup_aiohttp_apispec(
    ...
    error_callback=handle_validation_error,
)

=======

def format_http_error(http_error_cls, message: Optional[str] = None,
                      fields: Optional[Mapping] = None) -> HTTPException:
    status = HTTPStatus(http_error_cls.status_code)
    error = {
        'code': status.name.lower(),
        'message': message or status.description
    }

    if fields:
        error['fields'] = fields

    return http_error_cls(body={'error': error})


def handle_validation_error(error: ValidationError, *_):
    raise format_http_error(HTTPBadRequest, 'Request validation has failed', error.messages)


@middleware
async def error_middleware(request: Request, handler):
    try:
        return await handler(request)
    except HTTPException as err:
        if not isinstance(err.body, JsonPayload):
            err = format_http_error(err.__class__, err.text)
        raise err
    except ValidationError as err:
        raise handle_validation_error(err)
    except Exception:
        log.exception('Unhandled exception')
        raise format_http_error(HTTPInternalServerError)

@maximdanilchenko
Copy link
Owner

Oh, @elsimqoz, sorry, I missed that you wrote about response validation. Yes, aiohttp-apispec cannot validate responses. And I don’t think it is necessary. If you don’t think so you are welcome for PR’s:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants