feat(cli): add respect-per-spec-base-path setting for per-spec x-fern-base-path - #17495
Conversation
Docs Generation Benchmark ResultsComparing PR branch against median of 5 nightly run(s) on
Docs generation runs |
SDK Generation Benchmark ResultsComparing PR branch against median of 5 nightly run(s) on Full benchmark table (click to expand)
main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via |
efb5b22 to
250def4
Compare
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
250def4 to
b85eccc
Compare
Description
Linear ticket: Refs
An OpenAPI document's plain
x-fern-base-pathis stored as a single API-wide value on the IR. With multiple specs,merge()collapsed them (ir1.basePath ?? ir2.basePath), so one document's base path was silently dropped and the survivor was inlined into every endpoint path — including endpoints from other specs/namespaces, since the IR no longer records which document an endpoint came from.Reported by a customer with two specs: an OAuth spec (
x-fern-base-path: /, path/oauth/token) and their main API (x-fern-base-path: /api/v3)./won,/api/v3never reached the generated SDK, and nobase_urlworked for both: tenant root → API calls lose/api/v3(308),…/api/v3→ the token call becomes/api/v3/oauth/token(401). They were patching_build_urlin the generated client to work around it.This adds an opt-in OpenAPI setting,
respect-per-spec-base-path(defaultfalse), that applies each document's plain base path to that document's own endpoints during parsing, before the merge. With it enabled the customer case resolves tooauth/tokenandapi/v3/aa-sequence/itemsunder a tenant-rootbase_url. Default-off, so no existing output changes — anyone who compensated by putting the dropped prefix inbase_urlopts in and movesbase_urlback to the host root.Changes Made
openapi-ir-parser/src/openapi/v3/generateIr.ts: when the setting is on, prefix each converted endpoint path with the document's plain (non-parameterized)x-fern-base-pathand omit it from the document IR root;/stays a no-op and already-prefixed paths are not double-prefixed. Parameterized base paths (e.g./{tenant}/v1) still live at the root so their path params stay on the client. Webhooks are unchanged —WebhookWithExamplehas no path field.openapi-ir-parser/src/parse.ts: base-path merging moved intomergeBasePath(), which reports a conflict (context.failWithoutThrowing) when two documents declare differing parameterized base paths and the setting is on, instead of silently keeping one. With the setting off the oldir1.basePath ?? ir2.basePathbehavior is preserved exactly.respect-per-spec-base-path→respectPerSpecBasePaththrough the settings schemas, generators.yml definition + regenerated JSON schemas,convertGeneratorsConfiguration,getAPIDefinitionSettings,LegacyApiSpecAdapter, and parser options (mirrorsrespect-parameter-content).feat).Testing
per-spec-base-path(setting on:basePath: null,oauth/token,api/v3/items) andper-spec-base-path-disabled(setting off: old collapsed behavior). Pre-existing snapshots, incl.x-fern-base-path, are unchanged.fern iron a repro of the customer'sgenerators.yml. Setting on: top-levelbasePath: null, oauth endpointfullPath: oauth/token, main endpointfullPath: api/v3/aa-sequence/items, and theoauth::POST /oauth/tokenauth reference still resolves. Setting absent: identical tomain(oauth/token,aa-sequence/items).url-referencefixtures that require fetching a live GitHub URL.Note on php-sdk seed
The two new test-definitions fixtures are picked up by every generator's seed matrix, including php-sdk. The generated PHP fails
composer analyze(phpstan:Variable $clientId on left side of ?? always exists and is not nullable) because mandatory OAuth client credentials are non-nullable in the root client while the OAuth provider still emits$clientId ?? ''. That is a pre-existing PHP generator issue unrelated to this change (the-disabledfixture, which keeps the old behavior, fails identically), so both fixtures are added toseed/php-sdk/seed.ymlallowedFailuresalongside the existingcli-oauthentry.Written by Devin