From a7bc5b4ac603aca2e27da2a400fd93723f3c6802 Mon Sep 17 00:00:00 2001 From: RapidPoseidon Date: Fri, 24 Apr 2026 09:11:57 +0000 Subject: [PATCH] fix(client): url-encode query parameter names `parameters_to_url_query` quoted every value but pasted keys in raw, including the `multi` branch where the key was stringified without any encoding. A query name that contained `&`, `=`, `#`, a space, etc. would corrupt the query string (break at the `&`, fuse into the previous pair at `=`, silently truncate at `#`, etc.). Encode keys with the same `quote()` the values use. Mirrored into `openapi/templates/api_client.mustache`. Session: https://session-bc38cc85.poseidon.rapidata.internal/ Co-Authored-By: Claude Opus 4.7 Co-Authored-By: lino --- openapi/templates/api_client.mustache | 9 ++++++--- src/rapidata/api_client/api_client.py | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/openapi/templates/api_client.mustache b/openapi/templates/api_client.mustache index 3580c8ff9..727874c23 100644 --- a/openapi/templates/api_client.mustache +++ b/openapi/templates/api_client.mustache @@ -522,10 +522,13 @@ class ApiClient: if isinstance(v, dict): v = json.dumps(v) + encoded_key = quote(str(k)) if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, str(value)) for value in v) + new_params.extend( + (encoded_key, quote(str(value))) for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -536,10 +539,10 @@ class ApiClient: else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (encoded_key, delimiter.join(quote(str(value)) for value in v)) ) else: - new_params.append((k, quote(str(v)))) + new_params.append((encoded_key, quote(str(v)))) return "&".join(["=".join(map(str, item)) for item in new_params]) diff --git a/src/rapidata/api_client/api_client.py b/src/rapidata/api_client/api_client.py index 52710c19d..841818463 100644 --- a/src/rapidata/api_client/api_client.py +++ b/src/rapidata/api_client/api_client.py @@ -514,10 +514,13 @@ def parameters_to_url_query(self, params, collection_formats): if isinstance(v, dict): v = json.dumps(v) + encoded_key = quote(str(k)) if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, str(value)) for value in v) + new_params.extend( + (encoded_key, quote(str(value))) for value in v + ) else: if collection_format == 'ssv': delimiter = ' ' @@ -528,10 +531,10 @@ def parameters_to_url_query(self, params, collection_formats): else: # csv is the default delimiter = ',' new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) + (encoded_key, delimiter.join(quote(str(value)) for value in v)) ) else: - new_params.append((k, quote(str(v)))) + new_params.append((encoded_key, quote(str(v)))) return "&".join(["=".join(map(str, item)) for item in new_params])