Skip to content

fix(tools): send array query parameters as repeated keys in RestApiTool - #1135

Open
OsamaAnsar wants to merge 1 commit into
google:mainfrom
OsamaAnsar:fix/rest-api-tool-array-query-params
Open

OsamaAnsar wants to merge 1 commit into
google:mainfrom
OsamaAnsar:fix/rest-api-tool-array-query-params

Conversation

@OsamaAnsar

Copy link
Copy Markdown

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

No existing issue found (searched open and closed issues and PRs for rest_api_tool, query parameter, array, explode).

2. Or, if no issue exists, describe the change:

Problem:
prepareRequestParams in core/src/tools/openapi_tool/rest_api_tool.ts does queryParams.append(originalName, String(argValue)) for every query parameter, so non-scalar values are mangled:

  • an array [1, 2, 3] becomes ?id=1%2C2%2C3 (one comma-joined value)
  • an object {a: 1} becomes ?filter=%5Bobject+Object%5D, which is [object Object]

OpenAPI 3.0 query parameters default to style: form, explode: true, which serializes an array as id=1&id=2&id=3. adk-python passes the list to httpx, which repeats the key the same way (checked with httpx 0.28.1: {'id': [1, 2, 3]} gives ?id=1&id=2&id=3). The existing parity tests only cover an array request body, not an array query parameter.

Solution:
A small appendQueryParam helper in rest_api_tool.ts:

  • Array: one name=value pair per element. null and undefined elements are skipped and an empty array sends nothing (httpx does the same for an empty list).
  • Plain object (also as an array element): JSON.stringify, instead of [object Object].
  • Scalars: unchanged (String(value)).

Why JSON for objects: adk-python only gets a result here by accident (httpx sends the Python repr, filter=%7B%27a%27%3A+1%7D), so there is nothing to match. The spec default for an object would be a=1, which drops the parameter name and can collide with other parameters. JSON keeps the parameter name and is lossless. ApiParameter does not carry style/explode, so those are not honoured; this PR only makes the default (form, explode: true) correct and does not add other styles.

Path parameters are untouched (#638 is the separate path-encoding fix).

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Added a query parameter serialization block (8 tests) to core/test/tools/openapi_tool/rest_api_tool_test.ts.

Before/after, calling prepareRequestParams directly:

                 before                                         after
id=[1,2,3]       https://example.com/items?id=1%2C2%2C3         https://example.com/items?id=1&id=2&id=3
filter={a:1}     https://example.com/items?filter=%5Bobject+Object%5D   https://example.com/items?filter=%7B%22a%22%3A1%7D
flag=false       https://example.com/items?flag=false           https://example.com/items?flag=false

With only the rest_api_tool.ts change reverted, 7 of the 8 new tests fail (the 8th, the scalar regression guard, passes either way); with the change restored the whole core/test/tools/openapi_tool directory passes (19 files, 549 tests). prettier --check and eslint are clean on the touched files.

vitest run --project unit:core on my Windows machine: 5608 passed, 2 failed. The 2 failures (core/test/utils/file_utils_test.ts dangling symlink, core/test/cli/utils/logs_test.ts symlink) are EPERM: operation not permitted, symlink and fail the same way on an unmodified main; I did not run them on Linux or macOS. Because of this I left "All unit tests pass locally" unticked.

Manual End-to-End (E2E) Tests:

Not run against a live API. I only exercised prepareRequestParams (and thereby the URL it builds); I did not send a request to a real server, and did not run test:integration / test:e2e.

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

Behaviour change to be aware of: an array query value previously reached the server as one comma-joined value (id=1,2,3); it is now repeated keys. A server that relied on the comma form (style: form, explode: false) would need that style supported separately.

RestApiTool stringified every query value with String(), so an array
[1, 2, 3] became id=1%2C2%2C3 and an object became [object Object].
OpenAPI query parameters default to style: form, explode: true, and
adk-python hands lists to httpx, which repeats the key. Append one pair
per array element (skipping null/undefined, nothing for an empty array)
and JSON-encode objects.
@Varun-S10 Varun-S10 self-assigned this Oct 27, 2026
@Varun-S10

Copy link
Copy Markdown
Contributor

Hi @OsamaAnsar, thank you for raising the PR to fix the issue. We have reviewed the code changes and it does resolve the issue. I will escalate the PR to the team to review, thank you for your patience and understanding.
Hi @kalenkevich, could you please take a look?

@Varun-S10 Varun-S10 added the needs review [Status] The PR/issue is awaiting review from the maintainer label Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs review [Status] The PR/issue is awaiting review from the maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants