Skip to content

fix: validate generated OpenAPI spec against OAS 3.1 - #1277

Open
grdsdev wants to merge 8 commits into
masterfrom
feat/openapi-3-2-0
Open

fix: validate generated OpenAPI spec against OAS 3.1#1277
grdsdev wants to merge 8 commits into
masterfrom
feat/openapi-3-2-0

Conversation

@grdsdev

@grdsdev grdsdev commented Jul 28, 2026

Copy link
Copy Markdown

Summary

  • Declare OpenAPI 3.1.0 (up from 3.0.x) in src/app.ts / src/admin-app.ts, since 3.1's Schema Object is a full JSON Schema 2020-12 superset — needed because route schemas use type: [X, 'null'] instead of the OAS 3.0 nullable: true idiom. (Originally targeted 3.2.0; downgraded to 3.1.0 since most codegen tools don't support 3.2 yet — 3.1 already covers what we need.)
  • Convert route schemas from the OAS 3.0 nullable: true idiom to standard JSON Schema type: [X, 'null'].
  • Add src/scripts/validate-openapi.ts (npm run docs:validate), which validates both generated specs against the official OAS 3.1 meta-schema (@hyperjump/json-schema/openapi-3-1), including embedded Schema Objects.
  • Add a strict-dialect pass in the same script (unevaluatedProperties: false layered on the official OAS 3.1 dialect) that walks every embedded Schema Object and rejects unknown keywords — catches a regression back to the OAS 3.0 nullable idiom, which the official dialect alone permits silently.
  • Wire docs:validate into CI (.github/workflows/ci.yml), with VECTOR_ENABLED/ICEBERG_ENABLED set so those routes' schemas are included.

Test plan

  • npm run test:unit passes (public/admin app suites green).
  • npm run build / tsc -noEmit clean.
  • npm run docs:validate passes against the current generated specs.
  • Verified the strict pass actually catches regressions: reverted a schema to the old nullable: true idiom locally, confirmed docs:validate failed with the exact offending path, then reverted the test change.

@coveralls

coveralls commented Jul 28, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 30482055678

Coverage increased (+0.09%) to 80.408%

Details

  • Coverage increased (+0.09%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 12817
Covered Lines: 10745
Line Coverage: 83.83%
Relevant Branches: 7523
Covered Branches: 5610
Branch Coverage: 74.57%
Branches in Coverage %: Yes
Coverage Strength: 414.68 hits per line

💛 - Coveralls

@grdsdev
grdsdev marked this pull request as ready for review July 28, 2026 20:59
@grdsdev
grdsdev requested a review from a team as a code owner July 28, 2026 20:59
Comment thread src/app.ts Outdated
Comment thread src/scripts/validate-openapi.ts Outdated
Comment thread .github/workflows/ci.yml
Comment thread src/scripts/validate-openapi.ts Outdated
Comment thread package.json
grdsdev added 8 commits July 29, 2026 15:54
3.2 is a strict superset of 3.1 for our purposes; validated the
generated docs against the official OAS 3.2 meta-schema.
Builds both apps, fetches their /documentation/json, and validates
against the official OAS 3.2 meta-schema (@hyperjump/json-schema).
schema-base recursively validates Schema Objects against the OAS 3.2
dialect; schema alone only checks them as opaque objects.
OpenAPI 3.2 Schema Objects are pure JSON Schema 2020-12, which has no
nullable keyword — it's silently ignored, so these fields were
documented as non-nullable despite AJV still accepting null at
runtime. Use type: [X, 'null'] instead.
Most codegen tools don't support 3.2 yet; 3.1 already gives us JSON
Schema 2020-12 Schema Objects, which is all these route schemas need.
The official OAS 3.1 dialect permits unknown keywords in Schema
Objects, so a regressed `nullable: true` wouldn't fail validation.
Add a strict dialect overlay (unevaluatedProperties: false) and run
it against every embedded Schema Object found in the generated spec.
@grdsdev
grdsdev force-pushed the feat/openapi-3-2-0 branch from 1f665a7 to f514abb Compare July 29, 2026 18:54
@grdsdev
grdsdev requested a review from ferhatelmas July 29, 2026 18:57
@grdsdev grdsdev changed the title feat: bump OpenAPI spec to 3.2.0 fix: validate generated OpenAPI spec against OAS 3.1 Jul 29, 2026
Comment thread src/admin-app.test.ts

try {
const spec = app.swagger() as { openapi: string }
expect(spec.openapi).toBe('3.1.0')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

expect(JSON.stringify(spec)).not.toContain('"nullable"')

can we add this or similar that it doesn't regress?

Comment thread src/app.test.ts
await app.ready()

const spec = app.swagger() as { openapi: string }
expect(spec.openapi).toBe('3.1.0')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

similarly here

Comment on lines +71 to +74
if (parentKey === 'schema') {
out.push({ path, schema: node })
return
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this going to handle a mere field named schema?
we don't have at the moment but I guess it could be useful for iceberg at some point

type: ['string', 'null'],
pattern: '^[0-9]+(?:\\.[0-9]+)?(?:[gG][bB]|[mM][bB]|[kK][bB]|[bB])$',
examples: ['100MB'],
nullable: true,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

seems one is left behind

value: { type: 'number', finite: true, nullable: true },

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.

3 participants