Skip to content

Commit

Permalink
API: Allow [] for array query parameters
Browse files Browse the repository at this point in the history
(cherry picked from commit 467e041)
  • Loading branch information
Harald Wilhelmi authored and eboileau committed Oct 31, 2024
1 parent c32047b commit 8a24c63
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 10 deletions.
30 changes: 27 additions & 3 deletions server/src/scimodom/api/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def get_valid_bam_file(dataset, name) -> BamFile:


def get_valid_dataset_id_list_from_request_parameter(parameter: str) -> list[str]:
as_list = request.args.getlist(parameter, type=str)
as_list = get_unique_list_from_query_parameter(parameter, str)
if len(as_list) > MAX_DATASET_IDS_IN_LIST:
raise ClientResponseException(
400,
Expand Down Expand Up @@ -240,7 +240,7 @@ def get_valid_coords(taxa_id: int, context: int = 0) -> tuple[str, int, int, Str
if end > chrom_size:
end = chrom_size

return (chrom, start, end, strand_dto)
return chrom, start, end, strand_dto


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


def get_response_from_pydantic_object(obj: BaseModel):
return Response(response=obj.json(), status=200, mimetype="application/json")
return Response(
response=obj.model_dump_json(), status=200, mimetype="application/json"
)


def _is_valid_identifier(identifier, length):
Expand All @@ -303,3 +305,25 @@ def _validate_taxa_id(taxa_id: int) -> None:
taxa_ids = [d["id"] for d in utilities_service.get_taxa()]
if taxa_id not in taxa_ids:
raise ClientResponseException(404, "Unrecognized Taxa ID")


def get_unique_list_from_query_parameter(name: str, list_type):
"""
There seems to be some confusion how arrays should be transmitted as query parameters.
While most people seem to agree that the values are packed into multiple query parameters,
some (older?) implementations leave the original name, while newer ones insist on
adding square brackets '[]' at the end of the name, e.g. my_array = ['x', 'y'] may be
transmitted like this:
Old: ?my_array=x&my_array=y
New: ?my_array[]=x&my_array[]=y
Flask seems not to be aware of this. We don't care and allow both. Also, don't want
that our code breaks if Flask fixes this - so we ignore double results. So don't use this
function for lists, which are allowed to contain the same value multiple times.
"""
result_as_set = {
*request.args.getlist(name, type=list_type),
*request.args.getlist(f"{name}[]", type=list_type),
}
return list(result_as_set)
9 changes: 5 additions & 4 deletions server/src/scimodom/api/modification.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
get_optional_positive_int,
get_optional_non_negative_int,
validate_rna_type,
get_unique_list_from_query_parameter,
)
from scimodom.services.bedtools import BedToolsService, get_bedtools_service
from scimodom.utils.dtos.bedtools import Bed6Record
Expand Down Expand Up @@ -269,7 +270,7 @@ def _get_annotation_source():

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


def _get_gene_filters():
raw = request.args.getlist("geneFilter", type=str)
raw = get_unique_list_from_query_parameter("geneFilter", str)
if raw is None:
return []
return raw


def _get_gene_or_chrom_required() -> GeneSearch:
gene = request.args.getlist("geneFilter", type=str)
gene = get_unique_list_from_query_parameter("geneFilter", str)
if gene:
return GeneSearch(gene_filter=gene)
else:
Expand All @@ -302,7 +303,7 @@ def _get_gene_or_chrom_required() -> GeneSearch:


def _get_multi_sort(url_split: str = "%2B"):
raw = request.args.getlist("multiSort", type=str)
raw = get_unique_list_from_query_parameter("multiSort", str)
if raw is None or (len(raw) == 1 and raw[0] == ""):
return []
for i in raw:
Expand Down
7 changes: 4 additions & 3 deletions server/src/scimodom/api/utilities.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from flask import Blueprint, request, Response
from flask import Blueprint, Response
from flask_cors import cross_origin
from sqlalchemy.exc import NoResultFound

Expand All @@ -7,6 +7,7 @@
get_valid_taxa_id_from_string,
ClientResponseException,
validate_rna_type,
get_unique_list_from_query_parameter,
)
from scimodom.services.annotation import get_annotation_service, BIOTYPES
from scimodom.services.assembly import get_assembly_service
Expand Down Expand Up @@ -61,7 +62,7 @@ def get_selections():
@cross_origin(supports_credentials=True)
def get_genes():
file_service = get_file_service()
selection_ids = request.args.getlist("selection[]", type=int)
selection_ids = get_unique_list_from_query_parameter("selection", int)
try:
return file_service.get_gene_cache(selection_ids)
except FileNotFoundError:
Expand All @@ -70,7 +71,7 @@ def get_genes():

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

Expand Down

0 comments on commit 8a24c63

Please sign in to comment.