Skip to content

fix(cli): use schema-level examples for OpenAPI parameters - #17658

Open
willkendall01 wants to merge 2 commits into
mainfrom
devin/1788540366-param-schema-examples
Open

fix(cli): use schema-level examples for OpenAPI parameters#17658
willkendall01 wants to merge 2 commits into
mainfrom
devin/1788540366-param-schema-examples

Conversation

@willkendall01

@willkendall01 willkendall01 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Description

Linear ticket: Refs N/A

When an OpenAPI parameter has no example/examples of its own, AbstractParameterConverter.convertParameterExamples skipped straight to autogenerating an example from property types (e.g. {"dbx_account_id": "string"}), ignoring example/examples declared on the parameter's schema (including $ref'd object schemas used for JSON-encoded headers via respect-parameter-content).

Now the converter resolves the original parameter schema (following $ref alias chains, with a cycle guard) and, if it declares examples, uses those as userSpecifiedExamples before falling back to autogeneration:

convertParameterExamples({ schema, originalSchema })
  parameter.example / parameter.examples            -> userSpecifiedExamples
  if none: resolveChain(originalSchema).example(s)  -> userSpecifiedExamples   // new
  if none: autogenerate                             -> autogeneratedExamples

Changes Made

  • AbstractParameterConverter: pass originalSchema into convertParameterExamples; new resolveSchemaReferenceChain follows $ref$ref aliases; read schema-level examples via context.getExamplesFromSchema when the parameter has none.
  • parameter-content fixture: add examples to AccountPhotoGetArg and an X-Plant-Id header whose schema is PlantIdAlias -> PlantId (with example); snapshot updated.
  • New parameter-schema-examples.test.ts covering the JSON-encoded header case and the alias-chain case.
  • packages/cli/register openapi-from-flag-simple-ir.snap updated: userId path param's schema example: user123 is now reported as user-specified instead of autogenerated.
  • CLI changelog entry under packages/cli/cli/changes/unreleased/.
  • Updated README.md generator (N/A)

Testing

  • Unit tests added/updated — all packages/cli/** package tests pass locally (162 turbo tasks, excluding ete which needs a built CLI).
  • Manual testing completed

Link to Devin session: https://app.devin.ai/sessions/a8d6b5bbe5bf499ab4137b2172d4f5df
Open in Devin Desktop: https://app.devin.ai/desktop/session/a8d6b5bbe5bf499ab4137b2172d4f5df?variant=devin
Requested by: @willkendall01


Devin Review

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@nitpickybot nitpickybot Bot 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.

AI Review Summary

Small, focused change that falls back to schema-level examples for OpenAPI parameters before autogenerating. Logic looks correct; main nits are around the example-name generation loop and a subtle name-collision path with the earlier parameter-example naming.

  • 🔵 3 suggestion(s)

To request another review, comment /ai-review on this pull request.

Comment on lines +227 to +230
const exampleName = this.context.generateUniqueName({
prefix: `${this.parameter.name}_example`,
existingNames: Object.keys(v2Examples.userSpecifiedExamples)
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 suggestion

generateUniqueName is called with existingNames: Object.keys(v2Examples.userSpecifiedExamples), but this block only runs when that map is empty — so on the first iteration there are no existing names, and only subsequent iterations get uniqueness. That works, but it means the first schema example may collide with an autogenerated name later (${parameter.name}_example) if downstream code merges maps. Worth double-checking the naming convention matches what Api-Arg_example vs AccountPhotoGetArg_example_0 in the snapshot implies — the two differing conventions in the snapshot suggest two different code paths are producing names, which is easy to trip over later.

- circle_crop: false
dbx_account_id: "dbid:plant-fern-123"
expect_account_photo: true
size: 128x128

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 suggestion

size: 128x128 is unquoted here but the expected value is the string "128x128". YAML parses this as a string anyway, but quoting it (like dbx_account_id) makes the intent explicit and avoids surprises if the value ever becomes something like 128e2.

Suggested change
size: 128x128
size: "128x128"

Comment on lines +40 to +51
expect(endpoint).toBeDefined();

const header = endpoint?.headers.find((header) => getWireValue(header.name) === "Api-Arg");
expect(header).toBeDefined();

const expectedExample = {
circle_crop: false,
dbx_account_id: "dbid:plant-fern-123",
expect_account_photo: true,
size: "128x128"
};
expect(Object.values(header?.v2Examples?.userSpecifiedExamples ?? {})).toEqual([expectedExample]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 suggestion

Optional chaining after expect(...).toBeDefined() means a missing endpoint/header silently degrades into toEqual([]) failures elsewhere rather than a clear failure. Consider narrowing with a non-optional assertion (e.g. if (endpoint == null) throw ... or expect(header).toBeDefined(); const h = header!;) so the subsequent assertions actually test what they claim.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

Devin Review

…ate register snapshot

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Docs Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-09-04T04:06:24Z).

Fixture main PR Delta
docs 272.5s (n=5) 248.4s (35 versions) -24.1s (-8.8%)

Docs generation runs fern generate --docs --preview end-to-end against the benchmark fixture with 35 API versions (each version: markdown processing + OpenAPI-to-IR + FDR upload).
Delta is computed against the nightly baseline on main.
Baseline from nightly run(s) on main (latest: 2026-09-04T04:06:24Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-09-04 18:02 UTC

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

SDK Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-09-04T04:06:24Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
csharp-sdk square 99s (n=5) 120s (n=5) 66s -33s (-33.3%)
go-sdk square 149s (n=5) 311s (n=5) 128s -21s (-14.1%)
java-sdk square 238s (n=5) 283s (n=5) 220s -18s (-7.6%)
php-sdk square 77s (n=5) N/A 62s -15s (-19.5%)
python-sdk square 152s (n=5) 254s (n=5) 159s +7s (+4.6%)
ruby-sdk-v2 square 96s (n=5) 154s (n=5) 71s -25s (-26.0%)
rust-sdk square 208s (n=5) 228s (n=5) 185s -23s (-11.1%)
swift-sdk square 85s (n=5) 464s (n=5) 58s -27s (-31.8%)
ts-sdk square 178s (n=5) 184s (n=5) 127s -51s (-28.7%)

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 fern generate). main (E2E): full customer-observable time including build/test scripts (nightly baseline, informational). Delta is computed against generator-only baseline.
⚠️ = generation exited with a non-zero exit code (timing may not reflect a successful run).
Baseline from nightly runs on main (latest: 2026-09-04T04:06:24Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-09-04 18:03 UTC

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.

1 participant