Skip to content

fix(tools): send OpenAPI operations to their own declared servers - #8088

Open
julienparenti wants to merge 1 commit into
google:mainfrom
julienparenti:fix/openapi-server-overrides
Open

julienparenti wants to merge 1 commit into
google:mainfrom
julienparenti:fix/openapi-server-overrides

Conversation

@julienparenti

Copy link
Copy Markdown

Link to Issue or Description of Change

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

Problem:
OpenApiSpecParser reads the root servers[0].url once and uses it as the base_url of every operation. A path item or an operation that declares its own servers is still called on the root server. The OpenAPI spec says operation-level servers override path-level servers, which override the root servers.

Solution:
Resolve the base URL per operation, in spec order: operation servers, then path servers, then root servers, then "" as before. An empty servers list does not override the enclosing level. The first server of the selected list is used, the same rule the parser already applies to the root servers.

Requests to a per-operation server still go through the RestApiTool URL validation, including the private-network block, because that check runs on the final request URL.

Server variables ({var} templating) are out of scope; they were not handled at the root level either.

Testing Plan

Unit Tests:

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

Added to tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py:

  • test_operation_servers_override_path_and_root_servers
  • test_path_servers_override_root_servers
  • test_path_servers_apply_when_no_root_servers
  • test_empty_operation_servers_fall_back_to_path_servers

The four tests fail on main and pass with the fix. Related suites:

$ pytest tests/unittests/tools/openapi_tool tests/unittests/tools/apihub_tool tests/unittests/tools/application_integration_tool
569 passed, 67 warnings in 6.59s

Full suite on all supported versions:

$ tox -p auto
  py311: OK
  py312: OK
  py313: OK
  py314: OK
  congratulations :)

pre-commit run passes on the changed files. mypy on openapi_spec_parser.py reports the same 12 errors as on main, none on the changed lines.

Manual End-to-End (E2E) Tests:

Three local HTTP servers each answer with their own name. An OpenAPIToolset is built from a spec where /items GET declares operation servers, /items declares path servers, and /health relies on the root server. Each generated tool is called, so a real HTTP request is sent:

toolset = OpenAPIToolset(spec_dict=spec, allow_private_network_access=True)
for tool in await toolset.get_tools():
  print(await tool.call(args={}, tool_context=None))

Before (main):

list_items  -> served_by=root      path=/v1/items  expected=operation WRONG
add_item    -> served_by=root      path=/v1/items  expected=path      WRONG
health      -> served_by=root      path=/v1/health expected=root      OK

After:

list_items  -> served_by=operation path=/v3/items  expected=operation OK
add_item    -> served_by=path      path=/v2/items  expected=path      OK
health      -> served_by=root      path=/v1/health expected=root      OK

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.

@google-cla

google-cla Bot commented Nov 10, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

OpenApiSpecParser picked the root servers[0].url once and reused it for
every operation, so a path item or operation that declared its own
servers was still called on the root server. Per the OpenAPI spec,
operation-level servers override path-level servers, which override the
root servers. Resolve the base URL per operation in that order; an empty
servers list does not override the enclosing level.

Fixes google#8064
@julienparenti
julienparenti force-pushed the fix/openapi-server-overrides branch from 8c042cd to 518500c Compare November 10, 2026 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenAPI tools ignore operation- and path-level server overrides

2 participants