Skip to content

Commit

Permalink
Making sure all endpoints define at least the minimum common responses
Browse files Browse the repository at this point in the history
A common pitfall when using this package is the following: you define
an endpoint that can result in 400 Bad Request, but you forget to list 400
in the `responses` section of your endpoint in openapi.yaml. This package
then instead returns 500 Internal Server error, because it keeps the promise
that only defined responses will be allowed (unless you set
`enable_request_validation` to `False`, that is).

With this commit, all endpoints, by default need to have 200, 400 and 500
on the list of `responses` in openapi.yaml, otherwise the app won't start. Additionally, all
endpoints that accept a parameter, also need to have 404 on the list of
`responses`.

You can skip this check by setting `enable_endpoint_validation` to `False`.

Refs #22
Refs #49 (comment)
Refs #36
  • Loading branch information
zupo committed Dec 12, 2020
1 parent 60e803a commit f54e0aa
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Some notes:
Provided with `pyramid_openapi3` are a few validation features:
* incoming request validation (i.e. what a client sends to your app)
* outgoing response validation (i.e. what your app sends to a client)
* endpoint validation (i.e. your app registers routes for all defined API endpoints)
* endpoint validation (i.e. all endpoints define minimal responses and have routes registered)

These features are enabled as a default, but you can disable them if you need to:

Expand Down
36 changes: 31 additions & 5 deletions pyramid_openapi3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ def includeme(config: Configurator) -> None:
config.add_directive("pyramid_openapi3_spec", add_spec_view)
config.add_directive("pyramid_openapi3_spec_directory", add_spec_view_directory)
config.add_tween("pyramid_openapi3.tween.response_tween_factory", over=EXCVIEW)
config.add_subscriber(check_all_routes, ApplicationCreated)
config.add_subscriber(validate_routes, ApplicationCreated)
config.add_subscriber(validate_minimal_responses, ApplicationCreated)

if not config.registry.settings.get( # pragma: no branch
"pyramid_openapi3_extract_errors"
Expand Down Expand Up @@ -293,11 +294,11 @@ def openapi_validation_error(
return exception_response(status_code, json_body=errors)


def check_all_routes(event: ApplicationCreated):
"""Assert all endpoints in the spec are registered as routes.
def validate_routes(event: ApplicationCreated):
"""Assert all endpoints in the spec have a route registered for them.
Listen for ApplicationCreated event and assert all endpoints defined in
the API spec have been registered as Pyramid routes.
the API spec have been assigned a Pyramid route.
"""

app = event.app
Expand All @@ -313,7 +314,7 @@ def check_all_routes(event: ApplicationCreated):
if not app.registry.settings.get(
"pyramid_openapi3.enable_endpoint_validation", True
):
logger.info("Endpoint validation against specification is disabled")
logger.info("Endpoint validation is disabled")
return

# Sometimes api routes are prefixed with `/api/v1` and similar, using
Expand All @@ -338,3 +339,28 @@ def remove_prefixes(path):
missing = [r for r in paths if r not in routes]
if missing:
raise MissingEndpointsError(missing)


def validate_minimal_responses(event: ApplicationCreated):
"""Assert all endpoints in the spec have defined at least minimal responses.
By default this makes sure that all endpoints have the minimal required
responses defined in the spec: 200, 400 and 500
Additionally, all endpoints with parameters need to have 404 defined in the
spec.
Finally, it is possible to override the minimal required responses for
each endpoint by setting "pyramid_openapi3.endpoint_validation_overrides"
to {'/endpoint/path': {'post': [202, 400, 500]}}
"""
app = event.app
minimal_responses = app.registry.settings.get( # noqa
"pyramid_openapi3.endpoint_validation_minimal_responses", [200, 400, 500]
)
minimal_responses_with_parameters = app.registry.settings.get( # noqa
"pyramid_openapi3.endpoint_validation_minimal_responses_with_parameters", [404]
)
overrides = app.registry.settings.get( # noqa
"pyramid_openapi3.endpoint_validation_overrides", [404]
)
2 changes: 1 addition & 1 deletion pyramid_openapi3/tests/test_app_construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def test_disable_endpoint_validation(

app_config.make_wsgi_app()

assert "Endpoint validation against specification is disabled" in caplog.text
assert "Endpoint validation is disabled" in caplog.text


def test_unconfigured_app(
Expand Down

0 comments on commit f54e0aa

Please sign in to comment.