I have a simple service that expects a POST to a certain endpoint. There's 1 parameter in the requestBody of the POST ("customerId"), and also a header parameter ("Authorization").
If I turn on strict_validation=True and I send a valid request to the endpoint, I get: Extra formData parameter(s) customerId not in spec.
The customerId parameter _is_ in the spec, so Connexion should accept the post and call the endpoint's business logic, rather than returning a 400.
Returns:
{
"detail": "Extra formData parameter(s) customerId not in spec",
"status": 400,
"title": null,
"type": "about:blank"
}
I'm using this spec.yaml:
openapi: "3.0.0"
info:
title: Hello World
version: "2"
servers:
- url: /v1.0
paths:
/test:
post:
operationId: hello.test
summary: A test endpoint.
parameters:
# If this header param is here and `strict_validation` is enabled, Connexion gives a 400 error,
# even if you DO send `customerId`.
- name: Authorization
in: header
required: true
schema:
type: string
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
customerId:
type: string
required:
- customerId
responses:
"200":
description: OK.
"401":
description: Unauthorized.
And this app.py:
import connexion
def create_app():
cxn = connexion.FlaskApp(__name__.split('.')[0], specification_dir='.')
cxn.add_api('spec.yaml', strict_validation=True, arguments={'title': 'Hello World Example'})
return cxn.app
And hello.py is just:
def test(body) -> str:
return f"customerId is {body['customerId']}"
Then, send a (valid) request to the endpoint. I'm using the httpie utility, although you can exercise the bug with the SwaggerUI too.
http -v -f POST http://localhost:8000/v1.0/test "Authorization: Bearer abcd" "customerId=4"
You will see the 400 response mentioned above.
It seems like having the header in the spec is necessary to make the bug happen. If you take out the parameters: block, it works.
Output of the commands:
python --version:
Python 3.6.6
pip show connexion | grep "^Version\:"
Version: 2.3.0
Ping...
To add on this:
I've been digging in the source code a bit and it seems that it is running a ParameterValidator instead of a RequestBodyValidator when there are any parameters.
I think the bug is in this function but I'm not sure how it is supposed to work properly:
https://github.com/zalando/connexion/blob/c8d8973c7e390a5e2071c7b494dd7bd52bd55ff1/connexion/operations/abstract.py#L415-L429
@jmdejong Did you make any headway on this?
I see this error in 2.5.1 but not in 2.3.0.
~I think this might be fixed by #1110
There was a regression in 2.5.1 that propagated default values from any parameter type to all other parameters type (like query -> form)~
I was able to reproduce the bug on master.
I think the problem is here: https://github.com/zalando/connexion/blob/master/connexion/decorators/validation.py#L303
it seems to be looking for a key (formData) that is unique to openapi 2.0.
Please note that strict mode for connexion was intended to fix a shortcoming of the openapi2.0 spec, but the openapi3.0 spec has a built in notion of strict called additionalProperties.
The OAS3 way to do this is to add additionalProperties: false in the schema.
Thank you, @jmdejong, @dtkav and @hjacobs ! I'm hoping to try the new version of Connexion out soon, to confirm the fix in my codebase.
Just to clarify: I'm not a Connexion dev. I just encountered this bug too and dug into the codebase in order to try to make it easier for the developers to fix this.
There is still an instance of this line
spec_params = [x['name'] for x in self.parameters['formData']] in
the file
https://github.com/zalando/connexion/blob/master/connexion/decorators/validation.py
The problem still occurs. @hjacobs @dtkav
Are you running into the bug on the latest release?
that line should only apply to swagger2.
Most helpful comment
Please note that
strictmode for connexion was intended to fix a shortcoming of the openapi2.0 spec, but the openapi3.0 spec has a built in notion ofstrictcalledadditionalProperties.The OAS3 way to do this is to add
additionalProperties: falsein the schema.