oneOf in schema does not work on requestBody when this oneOf is nested under other schema defined in #/components/schemas/.
oneOf shall work when it is nested under other schema defined in #/components/schemas/.
The body does not contain the block use oneOf.
The following is python and schema used to reprocedure this issue.
When we send a post request to /bad endpoint with body {"oneof":{"name":"one"}}. The response becomes {} instead of {"oneof":{"name":"one"}}.
The response shall be the same as request because they use the same schema, and the request is not rejected due to schema error.
openapi: 3.0.0
info:
title: title
version: 0.0.0
paths:
/bad:
post:
summary: test
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/nested'
responses:
200:
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/nested'
operationId: test.post
components:
schemas:
nested:
type: object
properties:
oneof:
$ref: '#/components/schemas/oneof'
oneof:
discriminator:
propertyName: name
mapping:
one: '#/components/schemas/one'
two: '#/components/schemas/two'
oneOf:
- $ref: '#/components/schemas/one'
- $ref: '#/components/schemas/two'
one:
type: object
required:
- name
properties:
name:
type: string
pattern: ^one$
two:
type: object
required:
- name
properties:
name:
type: string
pattern: ^two$
import connexion
def post(body):
print('body = {}'.format(body))
return body, 200, {}
app = connexion.App(__name__)
app.add_api('test.yml', strict_validation=True, validate_responses=True)
app.run()
Output of the commands:
$ python --version
Python 3.6.4+
$ grep connexion Pipfile
connexion = {git = "https://github.com/zalando/connexion", ref = "62582643cbfca65b0cf0d54755f81f0e1a7d1f82"}
Interesting! Thanks for filing the issue. I'll try to reproduce it and report back.
It looks like the problem is here:
https://github.com/zalando/connexion/blob/6aafd33e4dcece168d44f38a7d11ab623f2a1a8b/connexion/operations/openapi.py#L248
I'll need to think on this a bit. It seems like we need a way to get the "matched" schema's properties, but Ideally we could lean on the jsonschema library. I'll check if it has a feature like that and report back.
just adding more context...
we need to be able to successfully call
def _get_val_from_param(self, value, query_defn):
query_schema = query_defn["schema"]
if is_nullable(query_schema) and is_null(value):
return None
if query_schema["type"] == "array":
return [make_type(part, query_schema["items"]["type"]) for part in value]
else:
return make_type(value, query_schema["type"])
when the query_defn (not a great variable name...) looks like this:
{
"schema" : {
"oneOf" : [
{
"type" : "object",
"properties" : {
"name" : {
"pattern" : "^one$",
"type" : "string"
}
},
"required" : [
"name"
]
},
{
"type" : "object",
"required" : [
"name"
],
"properties" : {
"name" : {
"type" : "integer"
}
}
}
]
}
}
The reason this breaks is because it fails to look up the type.
This is a challenge because we want to look up the type from the schema that successfully validated.
It seems like we need a way to collapse this defn by leveraging some jsonschema functionality before passing it in here.
Of course we don't usually need to make_type when the body is json, but I can imagine there is a case where this breaks with form_params. Maybe we can lean more heavily on coerce_type in validation...
@cziebuhr it sounds like you are working on this based on your comment in https://github.com/zalando/connexion/pull/789#issuecomment-442370836 (awesome)
Want me to assign this ticket it to you?
Seems to be a duplicate of #781. Please have a look at https://github.com/zalando/connexion/pull/789#issuecomment-442370836. This is another reason why I don't think that #789 will fix the issue for #781.
I don't think they are duplicates.
oneOf. The author of that ticket has already confirmed that #789 fixed their issued.AFAICT In order to support oneOf we need to implement logic based on the discriminator field, which you mentioned that you were working on.
IMHO oneOf should work out of the box (without discriminator). The only reason it doesn't work is extra logic in the _get_body_argument function which I still try to understand. Can you bring some light into the dark why the function is totally different to swagger 2? Swagger 2 directly passes the body arg to the handler function, so 'free form' data should always works.
@czchen @dtkav @cziebuhr Hm. I guess I find cheap solution:
Just add "type" key along oneOf expression. Like that:
data:
oneOf:
- $ref: '#/components/schemas/sportsman_career2'
- $ref: '#/components/schemas/sportsman_career1'
type: object
Cheers, luv.
I am facing the same issue. Has anyone found a solution to this ?
Bug is still unfixed... :(
Still unfixed
Anyone working on this? I am having the issue as well and I'm willing to help fix this.
Has anyone found a workaround until this is fixed?
@bolmstedt Use the oneOf keyword up in paths section rather the in the components section. This works, for example:
responses:
200:
description: new scrolling result
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/ResultsScrollingUsers'
- $ref: '#/components/schemas/QueryExecution'
@jasonrhaas This really works fine. Thanks for help.
I am having the same problem, but the workaround from @jasonrhaas does not work
get:
operationId: api.aggregation.get_hourly
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/aggregated-data"
description: aggregated measurement data of a vessel
summary: Get measurement data for a single vessel for the last hour, aggregated
parameters:
- in: query
name: measures
description: ids of measure_points to return
schema:
example: [1,2,3]
oneOf:
- type: string
enum: [all]
- type: array
items:
type: integer
I am having the same problem.
Same problem for me as well
Most helpful comment
@bolmstedt Use the
oneOfkeyword up inpathssection rather the in thecomponentssection. This works, for example: