This PR is a proposal to enforce defaults in json bodies.
The standard JsonRequestBodyValidator does not adapt the body. Instead, I added a DefaultsJsonRequestBodyValidator which does. The user can easily activate enforcing default by passing this Validator in a validator_map.
I would have liked connexion to have an enforce_defaults flag, but it would be hard to make this compatible with the validator_map argument.
This PR adds an interface for the ConnexionMiddleware, similar to the
interface of the Connexion Apps.
The Connexion Apps are now a simple wrapper around the
ConnexionMiddleware and framework app, delegating the work to the
middleware. This enables a similar interface and behavior for users when
using either the middleware or apps.
The arguments are repeated everywhere there is a user interface, but are
parsed in a central place. Repeating the arguments is not DRY, but
needed to provide users with IDE autocomplete, typing, etc. They are
parsed in a single `_Options` class, which also provides a mechanism to
set default options on an App level, and override them on the more
granular API level.
This makes the long list of provided parameters a lot more manageable,
so I would like to use it for the `Jsonifier` as well, and re-add the
`debug` and `extra_files` arguments which I have dropped in previous
PRs. I'll submit a separate PR for this.
I renamed the `options` parameter to `swagger_ui_options` since it only
contains swagger UI options. This is a breaking change though, and we'll
need to highlight this upon release.
We still have quite a lot of `App`, `MiddlewareApp`, and abstract
classes. It would be great if we could find a way to reduce those
further, or at least find better naming to make it more clear what each
one does 🙂 .
Finally, I added examples on how the middleware can be used with third
party frameworks under `examples/frameworks`. Currently there's an
example for Starlette and Quart, but this should be easy to extend. They
also show how the `ASGIDecorator` and `StarletteDecorator` from my
previous PR can be used.
This PR contains 2 main changes:
- Expose additional context. We now expose the scope, operation,
connexion context, and receive channel as context aware globals. This
makes them available to the decorators independent of the framework in
between. The user will also be able to use these.
I also implemented a `TestContext` class which can be used to populate
the context during testing. It's minimal, but can be extended towards
the future.
- Rename the decorators to be framework specific. This is part of a
bigger change for which I'll submit a follow up PR. I was working on
this first when it became clear that the context would need to be
extended, which is why this is already included.
This PR updates the examples for Connexion 3.0 and merges them for
OpenAPI and Swagger.
2 examples required some changes to make them work:
- The reverse proxy example required some fixes to the
SwaggerUIMiddleware to leverage the `root_path` correctly. This is
included in the PR.
- The enforced defaults example requires the json validator to adapt the
body and pass it on. We currently pass on the original body after
validation, and I'm not sure if we should change this. I'll submit a
separate PR to discuss this.
Fixes#1534
Changes proposed in this pull request:
- Adds a "native" async app based on lower level Starlette tools. It
leverages the routing already done in the middleware.
- Extracts code related to the parameter decorator out of the Operation
objects
There's some more work to be done, but this PR is already quite huge, so
I wanted to stop at a point where I got all the tests and a simple
example working.
- Still some general refactoring. I left some TODOs, and the Operation
classes are still relied on in too many places.
- Sync routes on an Async app should receive async decorators, so they
can access the body using `await`. The decorators should then run the
sync route in a threadpool to prevent blocking.
- We should be able to reuse the parameter decorator for all ASGI apps
since we're working with a Starlette Request which we can get directly
from the scope and receive channel, which we can make available as
context. This means we'll pass Starlette Datastructures to the view
functions (eg. FormData, UploadFiles, ...), but if this is opt-in, I
don't see any issue with this.
- We should be able to reuse the response parsing for Starlette apps as
well since it returns a StarletteResponse.
- We should test the AsyncApp as well. I'm hoping we can do this quite
quickly by generating a test client for it in the fixtures as well, but
in the long term some more work will be needed.
Fixes the problem of non-exceptional "exceptions" being recorded by
telemetry systems as a serious error. This expands on the changes made
in #1326. The intention of that other change seems to be making
telemetry systems like Sentry record serious errors. Diving into the
Sentry implementation even shows that the signalled exception is
recorded at "level" = "error".
The root of the problem is that exceptions are being used for control
flow, which is not ideal - convenient for app writers but not always for
library maintainers. The connexion BadRequestProblem and
NotFoundProblem, for example, should not be recorded as an error in a
telemetry system. In my case
[elastic-apm-python](https://github.com/elastic/apm-agent-python) is
receiving these signals and recording 4xx events as serious errors.
This pull request only propagates an exception signal to flask if it's a
serious error.
Aiohttp applications have a similar problem with exceptions being used
for control flow - the problems middleware will convert the exception
into an appropriate problem response but things like the elastic apm
python telemetry middleware will see that exception and record it as a
serious error. Interestingly aiohttp also uses exceptions for control
flow and the elastic apm agent was patched to specifically ignore aio
web exceptions below the 5xx status response range. Elastic apm and
sentry cannot be expected to be aware of non-serious control flow
exceptions used by various libraries though. So, a solution for Aiohttp
applications is a separate problem.
Co-authored-by: Enerqi <>
* Create MediaTypeDict class for range matching
* Extract parsing instead of using jsonifier
* Add default validator class as parameter defaults
* Clean up form validation
* Extract boilerplate code into Routed base classes
* Use typing_extensions for Python 3.7 Protocol support
* Use Mock instead of AsyncMock
* Extract response validation to middleware
* Refactor Request validation to match Response validation
* Factor out shared functionality
* Fix typo in TextResponseBodyValidator class name
* Fix string formatting
* Use correct schema to check nullability in response validation
* Extract boilerplate code into Routed base classes
* Use typing_extensions for Python 3.7 Protocol support
* Use Mock instead of AsyncMock
* Turn properties into class attributes
* Removed internal variable pass_context_arg_name
* fixed issue with personalized context name in tests
* restored code from pr suggestion
* restore decorator functionality
now the function accept a pass_context_arg boolean parameter,
instead of the pass_context_arg_name value
* Fixed security test checks, now passes tests
* Removed pass_context_arg, fixed security handler
fixed security handler as suggested
removed pass_context_arg as before
* Fix context injection test
Co-authored-by: Niels Dewulf <87133686+nielsbox@users.noreply.github.com>
Co-authored-by: Robbe Sneyders <robbe.sneyders@ml6.eu>
* Set up code skeleton for validation middleware
* Add more boilerplate code
* WIP
* Add ASGI JSONBodyValidator
* Revert example changes
* Remove incorrect content type test
Co-authored-by: Ruwan <ruwanlambrichts@gmail.com>
* Fix OpenAPI parameters containing other parameters
OpenAPI parameters can be unspecified and sometimes contain other
parameters. The current behavior is to assume it's a bracket parameter
and nest the containing parameter within the contained parameter, which
breaks the schema as the original parameter now seems to contain a
nested object.
We can avert this by checking for the presence of a '[' in the
parameter.
* Trigger Github workflow
Co-authored-by: Ricardo Piro-Rael <rpiro-rael@ironox.com>