connexion
connexion copied to clipboard
Query parameter objects are not 'exploded'
Description
Connexion does not respect the 'explode' feature for query parameters. As an example the query object from this stackflow answer can be used.
Expected behaviour
Connexion should parse and pass 3 query parameters in flat form. genre_id=1 author_id=1 title=foobar
Actual behaviour
The endpoint returns 400 BAD REQUEST with body:
{
"detail": "Extra query parameter(s) author_id, genre_id, title not in spec",
"status": 400,
"title": null,
"type": "about:blank"
}
Steps to reproduce
- Create an openapi specification with a simple endpoint and this query parameter definition:
parameters:
- in: query
name: values
schema:
type: object
properties:
genre_id:
type: integer
author_id:
type: integer
title:
type: string
style: form
explode: true
- Start the connexion server - with the default validators
- Issue a request to the endpoint with this query:
?genre_id=1&author_id=1&title=foobar
Additional info:
openapi version is "3.0.0"
Output of the commands:
-
python --version
Python 3.6.8 -
pip show connexion | grep "^Version\:"
Version: 2.2.0
@johannegger Looks like I'm dealing with the same issue, with the added complexity of the oneOf
property in the parameters. I'm trying to be able to deal with variable parameter combinations. I stumbled upon this StackOverflow answer that describes how to accomplish this with OA3, but I still can't seem to get it to play nice with Connexion.
The endgoal is to allow conditional query parameters, in this case one of the following combinations:
- ?sku=
- ?retailerId=
- ?sku=&retailerId=
- ?sku=®ionId=
I have the following in my yaml
paths:
/brand:
delete:
tags:
- pricing
summary: Delete existing Product Pricing
description: Acceptable queries:<br>`sku`+`retailerId` - Delete the pricing
of the product for a specific retailer. Removes this product from a retailer's
site.<br>`sku`+`regionId` - Delete the pricing of the product for a specific
region/price list. Removes this product from the region/price list.<br>`retailer`
- Delete all pricing for a specific retailer. Removes all products from a
retailer's site.<br>`sku` - Delete all pricing for the product. Removes the
product from all retailers' websites and all region/price lists.
# operationId: deletePricing
parameters:
- name: filter
in: query
style: form
explode: true
required: true
schema:
type: object
oneOf:
- $ref: '#/components/schemas/SingleSku'
- $ref: '#/components/schemas/SingleRetailer'
- $ref: '#/components/schemas/RetailerSku'
- $ref: '#/components/schemas/RegionSku'
additionalProperties: false
responses:
204:
description: Product pricing deleted
content: {}
401:
description: Invalid token supplied
content: {}
500:
description: Invalid query combination
content: {}
components:
schemas:
Id:
type: integer
format: int64
readOnly: true
Sku:
type: string
SingleSku:
title: Single Sku for All Retailers
description: Deletes the provided SKU from all Retailer price lists. This will remove the product from all Retailer sites.
type: object
properties:
sku:
allOf:
- $ref: '#/components/schemas/Sku'
required:
- sku
RetailerSku:
title: Single Sku for Retailer
description: Deletes the provided SKU from the provided Retailer's price list. This will only remove the product from that specific Retailer's site.
type: object
properties:
sku:
allOf:
- $ref: '#/components/schemas/Sku'
retailerId:
allOf:
- $ref: '#/components/schemas/Id'
required:
- sku
- retailerId
SingleRetailer:
title: All Pricing for Single Retailer
description: Deletes the provided Retailer's entire price list. This will remove all products from that specific Retailer's site.
type: object
properties:
retailerId:
allOf:
- $ref: '#/components/schemas/Id'
required:
- retailerId
RegionSku:
title: Single Sku for Region
description: Deletes the provided SKU from the provided Regional price list. This will remove the product from all Retailers' sites that are assigned to that Regional price list.
type: object
properties:
sku:
allOf:
- $ref: '#/components/schemas/Sku'
regionId:
allOf:
- $ref: '#/components/schemas/Id'
required:
- sku
- regionId
I'm using the MethodViewResolver and it routes to the following view.
from flask_restful import Resource
from flask import request
class BrandView(Resource):
def delete(self, filter=None):
print(filter)
print(request.args)
return request.args, 200
For testing, I just tried returning the args to make sure they're populating, but I never get that far. Using the first of the four variations of allowed parameter combinations (?sku=
), I tried just providing sku
in the swagger ui like so:
{"sku":"a"}
Which correctly corresponds to the produced request url http://127.0.0.1:5000/brand?sku=a
. But, I receive the validation error response saying the parameters don't match the spec
{
"detail": "Extra query parameter(s) sku not in spec",
"status": 400,
"title": null,
"type": "about:blank"
}
I also have strict_validation
set to True.
Thanks for the report @johannegger.
Connexion currently doesn't deserialize query objects with style: form
(the default) correctly, independent of the exploded
value. If you control the client, you can work around this by using style: deepObject
instead. More info on the style
values in the openapi docs.
Next to serialization, we should support the exploded
value in the strict_validation
as well.