Skip to content

feat(openapi): accept optional path params in the input schema - #1983

Merged
dinwwwh merged 4 commits into
middleapi:mainfrom
dinwwwh:claude/dynamic-params-schema-required-ab1808
Sep 5, 2026
Merged

feat(openapi): accept optional path params in the input schema#1983
dinwwwh merged 4 commits into
middleapi:mainfrom
dinwwwh:claude/dynamic-params-schema-required-ab1808

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Sep 5, 2026

Copy link
Copy Markdown
Member

The OpenAPI generator no longer throws when a dynamic path param is optional in the input schema. The router only reaches a procedure after the path matched, so the param is always present at runtime, and OpenAPI mandates required: true on path parameters anyway. The generator now emits that unconditionally instead of refusing to produce a document.

This also removes an inconsistency: detailed mode already tolerated an optional params section, and union inputs where only some branches carried the param were rejected even though the route physically requires the segment.

Behavior

  • Contracts with an optional path param field now generate, with the parameter documented as required: true.
  • Params missing from the input schema still throw.
  • Backward compatible: only contracts that previously threw are affected.

Testing

  • Unit tests cover compact and detailed inputs with an optional param.
  • An e2e test with zod .optional() verifies the generated parameter.
  • The routing docs no longer state that path param fields must be required.

The route only matches when the segment is present, so the generator documents the param as required instead of throwing when the schema marks it optional.
@pkg-pr-new

pkg-pr-new Bot commented Sep 5, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@1983

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@1983

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@1983

@orpc/client

npm i https://pkg.pr.new/@orpc/client@1983

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@1983

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@1983

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@1983

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@1983

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@1983

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@1983

@orpc/experimental-msw

npm i https://pkg.pr.new/@orpc/experimental-msw@1983

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@1983

@orpc/next

npm i https://pkg.pr.new/@orpc/next@1983

@orpc/node

npm i https://pkg.pr.new/@orpc/node@1983

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@1983

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@1983

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@1983

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@1983

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@1983

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@1983

@orpc/server

npm i https://pkg.pr.new/@orpc/server@1983

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@1983

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@1983

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@1983

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@1983

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@1983

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@1983

commit: 7a3f58b

@pullfrog pullfrog 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.

ℹ️ Minor suggestion only — the change is correct, consistent with the runtime, and well tested.

Reviewed changes

This run reviewed the full PR: relaxing the OpenAPI generator so an optional path-param field in the input schema no longer throws, with the parameter documented as required: true.

  • renderPathParameters (packages/openapi/src/openapi-generator-operation.ts) — removed the "optional in the input schema" OpenAPIGeneratorError; the parameter was already emitted with a hardcoded required: true, matching both the runtime invariant (a {param} route only matches when the segment is present) and the OpenAPI 3.x mandate that path params be required.
  • Unit tests (openapi-generator-operation.test.ts) — added compact and detailed cases asserting the optional param renders as required; removed the now-dead throws when case. Both new tests fail on the pre-change code, so they pin the behavior.
  • e2e test (crud.test.ts) — added a zod .optional() path-param case and rewrote the aggregated-error test to keep exercising the "missing from the input schema" throw.
  • Docs (routing.mdx) — dropped the "must be required" guidance in the path-parameters and prefixes sections.

I traced the surrounding surfaces to confirm consistency: the client codec (openapi-link-codec.ts) already rejects missing/empty path-param values at encode time ("Path param ... cannot be empty"), so the documented required: true matches actual runtime behavior; union inputs where the param is required only in some branches were previously rejected and now generate correctly; and no stale references to the removed error string remain in the repo. Tests pass and lint is clean.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread apps/content/docs/openapi/routing.mdx
@codspeed-hq

codspeed-hq Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing dinwwwh:claude/dynamic-params-schema-required-ab1808 (7a3f58b) with main (88ee055)

Open in CodSpeed

@codecov

codecov Bot commented Sep 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…optional path params

Exercises the handler, the link, and the generator for the pattern requested in middleapi#513.

@pullfrog pullfrog 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.

ℹ️ No issues in this delta — the new e2e test is well-constructed and genuinely pins the behavior, so no Fixing needed. Approval is withheld only because the one minor doc note from the prior review remains unaddressed.

Reviewed changes

This run covered the delta since the prior Pullfrog review (b0908b280880d3, one commit, one new file).

  • Added tests/openapi/reused-procedure-routes.test.ts — end-to-end coverage for #513: one procedure exposed under three routes where each route promotes a different optional field (tasting/user) to a path param. Exercises the handler (routing + coercion, e.g. /users/7/commentsuser: 7), the link (GET /tastings/42/comments, GET /users/me/comments?cursor=2, and the "Path param ... cannot be empty" rejection when the optional field is omitted), and the generator (each route documents path:{param}! as required, correct per-route query set, tags merged ['admin','tastings'], operationId tastings.listComments).

The generator assertions fail on the pre-change code (which threw OpenAPIGeneratorError for optional path-param fields), so this test genuinely pins the fix rather than rubber-stamping it. Assertions match what the prior review confirmed about the runtime codec and the always-required rendering.

Pullfrog  | Fix it ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog 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.

✅ No new issues found. The one open thread from the prior review is now addressed, so the doc-only delta is good to merge.

Reviewed changes

This run reviewed the delta since the prior Pullfrog review (80880d3f759084, one commit).

  • Added a docs note in routing.mdx — "Path parameters are always documented as required, even when the schema field is optional, because the route only matches when the segment is present" — exactly the note the prior review suggested, so users writing z.string().optional() won't be surprised by their generated document.
  • Reworded the source comment in openapi-generator-operation.ts:224 to the single-line form; confirmed the removed entry[2] check leaves no dead/unused references (entry[1] still feeds the schema).

The documentation now matches the generator behavior (required: true emitted unconditionally) and the prior thread is resolved.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@dinwwwh
dinwwwh merged commit 6f5501f into middleapi:main Sep 5, 2026
8 checks passed
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