Skip to content

feat: add CI-level OpenAPI documentation validation#2112

Open
rainer-friederich wants to merge 4 commits intomainfrom
feat/validate-openapi-schema
Open

feat: add CI-level OpenAPI documentation validation#2112
rainer-friederich wants to merge 4 commits intomainfrom
feat/validate-openapi-schema

Conversation

@rainer-friederich
Copy link
Copy Markdown
Contributor

@rainer-friederich rainer-friederich commented Apr 2, 2026

Summary

  • Layer 1 — Route coverage (unit tests): Fails CI when code routes lack OpenAPI documentation or vice versa. Explicit allowlist for 61 currently undocumented routes with a ratchet mechanism that prevents the count from growing.
  • Layer 2 — Response schema validation (IT tests): Validates actual API response bodies against declared OpenAPI schemas using AJV, proving output types and required fields are correct.
  • Layer 2 — Request schema validation (IT tests): Validates request bodies against declared OpenAPI requestBody schemas, proving input types and required fields are documented correctly.
  • Layer 2 — Strict response mode (IT tests): Injects additionalProperties: false into object schemas to catch undocumented fields leaking through DTOs that are missing from the spec.
  • Both layers run within existing CI pipeline (npm test and it-postgres) — no workflow changes needed

New assertion helpers for IT tests

Helper Purpose
expectSchemaValid(res, method, path) Validates response body matches declared schema (types, required fields)
expectSchemaValidStrict(res, method, path) Same + rejects undocumented fields not in the schema
expectRequestSchemaValid(body, method, path) Validates request body matches declared requestBody schema

Test plan

  • npm test passes (7182 tests, including 7 new OpenAPI coverage tests)
  • npm run lint passes
  • IT tests (npx mocha --require test/it/postgres/harness.js --timeout 30000 'test/it/postgres/sites.test.js') validate schema assertions
  • Verify removing an OpenAPI path causes the coverage test to fail
  • Verify adding a new route without OpenAPI docs causes the coverage test to fail
  • Verify expectSchemaValidStrict catches undocumented response fields
  • Verify expectRequestSchemaValid catches request body type mismatches

🤖 Generated with Claude Code

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 2, 2026

This PR will trigger a minor release when merged.

Add two validation layers to ensure OpenAPI specs stay in sync with code:

Layer 1 (unit tests): Route coverage test that verifies every code route
has a corresponding OpenAPI path entry and vice versa. Uses an explicit
allowlist for 61 currently undocumented routes with a ratchet mechanism
that prevents the count from growing.

Layer 2 (IT tests): Response schema validation using AJV that validates
actual API response bodies against declared OpenAPI schemas. Added as
proof-of-concept to 6 sites endpoint test cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@rainer-friederich rainer-friederich force-pushed the feat/validate-openapi-schema branch from c542f4d to a1a32bb Compare April 2, 2026 11:59
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

rainer-friederich and others added 3 commits April 2, 2026 12:21
Extend Layer 2 schema validation with two new capabilities:

- Request body validation (expectRequestSchemaValid): validates that
  request bodies sent in IT tests conform to the declared OpenAPI
  requestBody schema, proving input types and required fields are
  documented correctly.

- Strict response validation (expectSchemaValidStrict): injects
  additionalProperties: false into object schemas that don't
  explicitly set it, catching undocumented fields leaking through
  DTOs that are missing from the OpenAPI spec.

Both are wired into sites IT tests as proof-of-concept.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The @redocly/cli bundle command uses --ext (not --format) to specify
the output file extension. The --format flag does not exist and causes
CI to fail with "Unknown argument: format".

Also writes the bundled spec to a temp file instead of stdout to avoid
potential encoding issues, and gitignores the generated artifact.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The bundled spec must be fully dereferenced (no $ref pointers) for AJV
to compile schemas. Without --dereferenced, schemas contain references
like #/components/schemas/Site that AJV cannot resolve when compiling
individual response/request schemas.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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