Skip to content

feat(routes): add opt-in route prefix resolution from host.json - #869

Merged
yeongseon merged 11 commits into
mainfrom
feat/route-prefix-resolution
Oct 30, 2026
Merged

yeongseon merged 11 commits into
mainfrom
feat/route-prefix-resolution

Conversation

@yeongseon

@yeongseon yeongseon commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

Summary

The URL prefix the Functions host serves HTTP triggers under (host.json, extensions.http.routePrefix) had to be repeated as route_prefix= and --route-prefix, and nothing detected a mismatch. This adds opt-in resolution and a CLI warning without changing any default.

Changes

  • New public helper resolve_route_prefix(host_json=None). It returns the effective prefix: the AzureFunctionsJobHost__extensions__http__routePrefix app setting if present, then extensions.http.routePrefix from the given host.json (default ./host.json), then /api. The result is normalized for every existing route_prefix parameter, an empty prefix is honored at each level, a missing file or key falls back silently, and an unreadable or malformed file warns with RuntimeWarning and falls back. The file is parsed as strict JSON with an optional UTF-8 byte order mark. It never imports or executes application code.
  • CLI: --route-prefix auto uses the helper with the host.json beside the imported --app module (the current directory otherwise). The default is still /api; a literal prefix named auto is written /auto.
  • CLI: without auto, a host.json prefix that differs from the effective prefix produces a structured route-prefix-mismatch warning (new WarningCode) on stderr, and it gates --fail-on-warnings. The check reads the file only, and missing, malformed or unreadable files never produce it.
  • Docs: route prefix guide, getting-started, CLI, API reference, README, DESIGN.md and the LLM references. The repository's formatter hook also re-indented one closing parenthesis in docs/getting-started.md and one comment in docs/route-prefix.md (whitespace only).
  • The decision behind this design is recorded in a comment on #859.

Validation

Run locally on 1c5b4fa:

  • make check-all: exit 0 (1700 passed, 30 skipped). The skipped tests need the optional azure-functions-validation package, which the Hatch environment does not install. Coverage is 95.39% (gate: 95%).
  • mkdocs build --strict: exit 0. The new test files also pass on Python 3.14.
  • End to end in a throwaway project whose host.json sets routePrefix to v1: the mismatch warning with exit 0; exit 2 with --fail-on-warnings and no output file; --route-prefix auto giving /v1/... paths, also when host.json starts with a byte order mark; an explicit /v1 without a warning; the app-setting override, including an empty value; a host.json without routePrefix; and the Swagger UI URL /v1/openapi.json when resolve_route_prefix feeds register_openapi_routes.
  • The new tests fail when the behavior they cover is removed: app-setting precedence, the mismatch warning, byte order mark handling, the module-directory lookup, the warning gate and the unreadable-file warning.
  • GitHub CI on 1c5b4fa: all check runs completed with no failures, including the required Analyze, bandit, ci-required, PR title and semgrep contexts.
  • Review: an independent AI review (advisory) covered the branch through c5683c0 and found no blocking issues; its notes are applied, and the last commit (1c5b4fa) only rewords one sentence in docs/route-prefix.md. DESIGN.md and docs/cli.md are policy-bearing files, so a maintainer review of the final head is still needed.

Compatibility

  • No existing default or signature changes. resolve_route_prefix and WarningCode.ROUTE_PREFIX_MISMATCH are additions.
  • CLI jobs that run generate --fail-on-warnings in a project whose host.json prefix differs from the effective prefix now exit 2. That is the drift this detects; fix it with --route-prefix <value> or --route-prefix auto.
  • An explicit --route-prefix that differs from host.json is still honored for the generated paths, but it also produces the warning. A job that intentionally documents a gateway-facing prefix should therefore not use --fail-on-warnings.
  • auto is now a reserved --route-prefix value.
  • host.json is looked up beside the imported --app module, so a module inside a package reads the file in that package directory, not the project root.
  • Known limit, documented in the route prefix guide: with auto, an unreadable or malformed host.json falls back to /api with a RuntimeWarning that does not gate --fail-on-warnings. A file with comments or trailing commas counts as malformed, although the Functions host may accept it. This follows the decision recorded on feat(routes): read the host.json route prefix instead of duplicating it in code and CLI flags #859; a hard error or a gating warning in auto mode would be a small follow-up if you prefer it.
  • How the Functions host treats an empty app setting is not verified, so the docs only describe the helper's rule for it.
  • Mismatch warnings for the Python API are out of scope: those signatures default to a literal /api, so an explicit value cannot be told apart from the default.

Related Issues

Closes #859

yeongseon and others added 7 commits October 30, 2026 19:48
Add an opt-in helper that returns the effective route prefix without duplicating it in code. The AzureFunctionsJobHost__extensions__http__routePrefix app setting wins, then extensions.http.routePrefix from the given host.json (default ./host.json), then /api. The result is normalized for every existing route_prefix parameter, an empty prefix is honored at each level, and an unreadable or malformed file warns with RuntimeWarning and falls back. No existing default or signature changes. Refs #859

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
…mismatch

Let --route-prefix auto resolve the prefix from the host.json beside the imported --app module (current directory otherwise), honoring the app-setting override. Without auto, a host.json prefix that differs from the effective one now produces a structured route-prefix-mismatch warning that gates --fail-on-warnings. The check reads the file only, and missing, malformed or unreadable files never produce it. The default stays /api. Refs #859

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Add the resolution section to the route prefix guide with the precedence, the function_app.py usage and the app-setting override, point the getting-started guide at it, and add the helper to the API reference. Refs #859

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Describe the auto value, the literal /auto prefix, the route-prefix-mismatch warning and its exit code 2 behavior under --fail-on-warnings. Refs #859

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
…notes

Mention the opt-in helper and the CLI auto value in the README, and record in the design notes that detection is opt-in and that Python APIs do not warn about mismatches. Refs #859

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
List the new public helper and the CLI behavior in llms.txt and llms-full.txt. Refs #859

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
A host.json saved with a UTF-8 byte order mark, as some Windows editors do, made resolve_route_prefix warn and fall back to /api. Decode with utf-8-sig so the file is read, add a regression test, and document that the file is parsed as strict JSON, so comments and trailing commas are still reported as unreadable. Refs #859

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues are identified for the opt-in route-prefix resolution change.

No open issues 🎉

What changed in this PR

Adds opt-in route-prefix resolution to align generated OpenAPI paths and Swagger UI URLs with Azure Functions configuration, while preserving the /api default.

Changes:

  • Exports resolve_route_prefix() with app-setting precedence, host.json fallback, normalization, and invalid-file diagnostics.
  • Adds CLI --route-prefix auto and structured mismatch warnings that gate --fail-on-warnings.
  • Adds regression coverage and documents configuration, discovery rules, and compatibility.
File Description
tests/​test_spec_warnings.py Checks the new warning code’s serialized value.
tests/​test_public_api.py Verifies the helper is publicly exported.
tests/​test_host_config.py Covers precedence, normalization, fallback, and diagnostics.
tests/​test_docs_routes_host_config.py Checks Swagger URLs use resolved prefixes.
tests/​test_cli_host_config.py Covers automatic resolution, discovery, and warning gating.
src/​azure_functions_openapi/​host_config.py Implements configuration reading and prefix resolution.
src/​azure_functions_openapi/​cli.py Integrates resolved prefixes and mismatch warnings.
src/​azure_functions_openapi/​_warnings.py Adds ROUTE_PREFIX_MISMATCH.
src/​azure_functions_openapi/​_cli_route_prefix.py Implements CLI discovery and mismatch detection.
src/​azure_functions_openapi/​__init__.py Exports resolve_route_prefix.
README.md Introduces opt-in prefix detection.
llms.txt Summarizes the new public helper.
llms-full.txt Documents resolution and CLI warning behavior.
docs/​route-prefix.md Explains precedence, usage, and compatibility.
docs/​getting-started.md Adds helper-based route configuration guidance.
docs/​cli.md Documents automatic resolution and warning exit behavior.
docs/​api.md Adds the helper reference and mismatch-warning scope.
DESIGN.md Records the opt-in compatibility policy.

Review effort: Balanced

yeongseon and others added 4 commits October 30, 2026 20:44
…ilter-independent

Pin that --route-prefix auto falls back to /api with a RuntimeWarning and does not gate --fail-on-warnings when host.json is unreadable, so any change to that policy is deliberate. Record warnings with the always filter in the absent-configuration test so its empty-list assertion cannot pass because a filter hid the warning. Refs #859

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Say that the helper treats a present but empty app setting as no prefix without claiming how a hosting environment delivers it, and document that --route-prefix auto falls back to /api with a RuntimeWarning that does not gate --fail-on-warnings when host.json cannot be read. Refs #859

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Align the route prefix guide with the CLI guide so a missing host.json is not read as one of the cases that prints the RuntimeWarning in --route-prefix auto mode. Refs #859

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
@yeongseon
yeongseon merged commit 28a17ab into main Oct 30, 2026
29 checks passed
@yeongseon
yeongseon deleted the feat/route-prefix-resolution branch October 30, 2026 14:08
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.

feat(routes): read the host.json route prefix instead of duplicating it in code and CLI flags

2 participants