Closed tschaffter closed 3 years ago
Current query parameter:
name: status
description: Array of challenge status used to filter the results
in: query
required: false
schema:
type: array
items:
$ref: ../../../components/parameters/ChallengeStatus.yaml
The Swagger UI knows that this parameter can take an array as value but the UI component does not allow to specify more than once status.
TODO: Check that the API service and client work as expected with the current approach. Otherwise an alternative would be to use items: type: string
.
Multiple status
value can be passed via the URL. Validation is also nicely performed and status=plop
is reported as invalid. Thus it would be a shame to have to use items: type: string
and no longer benefit from the validation. Still have to test that an array can be passed to the rocc-client-angular.
Here is how to filter challenges so that challenges that have AT LEAST ONE of the tag ids specified will be returned:
tag_ids_q = Q(tagIds__in=tag_ids) \
if tag_ids is not None and len(tag_ids) > 0 else Q()
Note: The AND behavior can be achieved with tagIds__all
so that all the tags of a challenge must be included in the specified list of tags.
MongoDB has a convenient feature to search for terms among multiple properties. I'm heading toward enable the user to specify multiple search terms as a single string, which will be passed to MongoDB to search challenges that have these terms in Challenge.name
and Challenge.description
.
https://swagger.io/docs/specification/serialization/
Related discussion on the serialization of nested objects: https://github.com/OAI/OpenAPI-Specification/issues/1706
Problem
Here is an example
filter
object passed as query parameter when fetching a page of challenges:This query parameter currently uses the following serialization options:
This configuration generates the follow request URL:
http://localhost:8080/api/v1/challenges?limit=10&filter%5BtagIds%5D=tag1&filter%5BtagIds%5D=tag2
http://localhost:8080/api/v1/challenges?limit=10&filter[tagIds]=tag1&filter[tagIds]=tag2
(same URL but more readable)The error returned by the API service is:
"'tag1' is not of type 'array'...
Solutions
It seems that there is no easy solution for serializing deep objects. See https://github.com/OAI/OpenAPI-Specification/issues/1706. Ideally we want to continue to leverage the automatic generation of the API service and customize its code only if required.
The easiest solution seems to flatten the query by removing the
filter
level and instead specify directly a query parameter namedtagIds
, for example.Example of query with
explode: true
: http://localhost:8080/api/v1/challenges?limit=10&tagIds=tag1&tagIds=tag2 Example of query withexplode: false
: http://localhost:8080/api/v1/challenges?limit=10&tagIds=tag1,tag2Data received by the challenge controller when using
style: form
andexplode: false
(default behavior for query parameters) orexplode: true
.Notes
explode: true
enables value to include a "comma" since the comma is not used as separator in this mode. This could be useful for free text search (in this case it's probably better to send the entire string and let the API service tokenize the string using space, for example).explode: true
and the use of the plural form for the variable (heretagIds
, the query parameter being an array) leads to a slight naming inconsistency as intagIds=tag1&tagIds=tag2
. This inconsistency disappear when usingexplode: false
=>tagIds=tag1,tag2
.explode: false
contributes to make URL shorter.Solution 1
Keep the object
ChallengeFilter
for now for properties that represent a single value. The following properties that were inChallengeFilter
are not single values and so are made individual query parameters:Other properties my follow (e.g.
organizers
) and potentially lead to completely dropping theChallengeFilter
object and other{schema}Filter
.Solution 2
Keep
ChallengeFilter
and makeChallengeFilter.tagIds
a single string value. The client is responsible for concatenating multiple values using a delimiter, e.g a comma. All clients and the API service must then use the same delimiter. This issue with this approach is that the OpenAPI specification can not enforce this requirement. At best this can be capture in the description of the query parameter.Because the resulting URLs are less standard than in Solution 1, the following pain point may be introduced for the web client: when someone bookmark or share a URL that include parameter, the ideal behavior is that UI of the filters on the page is initialized based on the values of the query parameters. Similarly to the extra code that we would add in Solution 2 to concatenate multiple values, we would need to write code that un-concatenate values of query parameters when the page load.
Conclusion
I propose to adopt Solution 1, which will be implemented in this PR.
EDIT: Since most of the parameters in
ChallengeFilter
are meant to take arrays, I may just dropChallengeFilter
.Tagging @vpchung @rrchai for comments
Update
ChallengeFilter
.