Skip to content

Commit 8a24c63

Browse files
Harald Wilhelmieboileau
authored andcommitted
API: Allow [] for array query parameters
(cherry picked from commit 467e041)
1 parent c32047b commit 8a24c63

File tree

3 files changed

+36
-10
lines changed

3 files changed

+36
-10
lines changed

server/src/scimodom/api/helpers.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def get_valid_bam_file(dataset, name) -> BamFile:
9898

9999

100100
def get_valid_dataset_id_list_from_request_parameter(parameter: str) -> list[str]:
101-
as_list = request.args.getlist(parameter, type=str)
101+
as_list = get_unique_list_from_query_parameter(parameter, str)
102102
if len(as_list) > MAX_DATASET_IDS_IN_LIST:
103103
raise ClientResponseException(
104104
400,
@@ -240,7 +240,7 @@ def get_valid_coords(taxa_id: int, context: int = 0) -> tuple[str, int, int, Str
240240
if end > chrom_size:
241241
end = chrom_size
242242

243-
return (chrom, start, end, strand_dto)
243+
return chrom, start, end, strand_dto
244244

245245

246246
def get_valid_logo(motif: str) -> Path:
@@ -287,7 +287,9 @@ def get_optional_positive_int(field: str) -> int | None:
287287

288288

289289
def get_response_from_pydantic_object(obj: BaseModel):
290-
return Response(response=obj.json(), status=200, mimetype="application/json")
290+
return Response(
291+
response=obj.model_dump_json(), status=200, mimetype="application/json"
292+
)
291293

292294

293295
def _is_valid_identifier(identifier, length):
@@ -303,3 +305,25 @@ def _validate_taxa_id(taxa_id: int) -> None:
303305
taxa_ids = [d["id"] for d in utilities_service.get_taxa()]
304306
if taxa_id not in taxa_ids:
305307
raise ClientResponseException(404, "Unrecognized Taxa ID")
308+
309+
310+
def get_unique_list_from_query_parameter(name: str, list_type):
311+
"""
312+
There seems to be some confusion how arrays should be transmitted as query parameters.
313+
While most people seem to agree that the values are packed into multiple query parameters,
314+
some (older?) implementations leave the original name, while newer ones insist on
315+
adding square brackets '[]' at the end of the name, e.g. my_array = ['x', 'y'] may be
316+
transmitted like this:
317+
318+
Old: ?my_array=x&my_array=y
319+
New: ?my_array[]=x&my_array[]=y
320+
321+
Flask seems not to be aware of this. We don't care and allow both. Also, don't want
322+
that our code breaks if Flask fixes this - so we ignore double results. So don't use this
323+
function for lists, which are allowed to contain the same value multiple times.
324+
"""
325+
result_as_set = {
326+
*request.args.getlist(name, type=list_type),
327+
*request.args.getlist(f"{name}[]", type=list_type),
328+
}
329+
return list(result_as_set)

server/src/scimodom/api/modification.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
get_optional_positive_int,
2323
get_optional_non_negative_int,
2424
validate_rna_type,
25+
get_unique_list_from_query_parameter,
2526
)
2627
from scimodom.services.bedtools import BedToolsService, get_bedtools_service
2728
from scimodom.utils.dtos.bedtools import Bed6Record
@@ -269,7 +270,7 @@ def _get_annotation_source():
269270

270271
# TODO: for mod, org, and tech, we should in fact check that they exists in the DB...
271272
def _get_technology_ids():
272-
raw = request.args.getlist("technology", type=int)
273+
raw = get_unique_list_from_query_parameter("technology", int)
273274
if raw is None:
274275
return []
275276
for i in raw:
@@ -279,14 +280,14 @@ def _get_technology_ids():
279280

280281

281282
def _get_gene_filters():
282-
raw = request.args.getlist("geneFilter", type=str)
283+
raw = get_unique_list_from_query_parameter("geneFilter", str)
283284
if raw is None:
284285
return []
285286
return raw
286287

287288

288289
def _get_gene_or_chrom_required() -> GeneSearch:
289-
gene = request.args.getlist("geneFilter", type=str)
290+
gene = get_unique_list_from_query_parameter("geneFilter", str)
290291
if gene:
291292
return GeneSearch(gene_filter=gene)
292293
else:
@@ -302,7 +303,7 @@ def _get_gene_or_chrom_required() -> GeneSearch:
302303

303304

304305
def _get_multi_sort(url_split: str = "%2B"):
305-
raw = request.args.getlist("multiSort", type=str)
306+
raw = get_unique_list_from_query_parameter("multiSort", str)
306307
if raw is None or (len(raw) == 1 and raw[0] == ""):
307308
return []
308309
for i in raw:

server/src/scimodom/api/utilities.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from flask import Blueprint, request, Response
1+
from flask import Blueprint, Response
22
from flask_cors import cross_origin
33
from sqlalchemy.exc import NoResultFound
44

@@ -7,6 +7,7 @@
77
get_valid_taxa_id_from_string,
88
ClientResponseException,
99
validate_rna_type,
10+
get_unique_list_from_query_parameter,
1011
)
1112
from scimodom.services.annotation import get_annotation_service, BIOTYPES
1213
from scimodom.services.assembly import get_assembly_service
@@ -61,7 +62,7 @@ def get_selections():
6162
@cross_origin(supports_credentials=True)
6263
def get_genes():
6364
file_service = get_file_service()
64-
selection_ids = request.args.getlist("selection[]", type=int)
65+
selection_ids = get_unique_list_from_query_parameter("selection", int)
6566
try:
6667
return file_service.get_gene_cache(selection_ids)
6768
except FileNotFoundError:
@@ -70,7 +71,7 @@ def get_genes():
7071

7172
@api.route("/biotypes/<rna_type>", methods=["GET"])
7273
@cross_origin(supports_credentials=True)
73-
def get_biotypes(rna_type):
74+
def get_biotypes(rna_type): # noqa
7475
# TODO: do biotypes also depend on RNA type/annotation?
7576
return {"biotypes": MAPPED_BIOTYPES}
7677

0 commit comments

Comments
 (0)