Skip to content

feat(api): add OpenAPI contract validation - #1253

Merged
mijinummi merged 1 commit into
MDTechLabs:mainfrom
Cybermaxi7:feat/openapi-contract-validation
Sep 29, 2026
Merged

mijinummi merged 1 commit into
MDTechLabs:mainfrom
Cybermaxi7:feat/openapi-contract-validation

Conversation

@Cybermaxi7

Copy link
Copy Markdown
Contributor

Closes #1248

The problem

The OpenAPI document is built at runtime from @nestjs/swagger decorators in apps/api/src/main.ts and served at /api/docs. Nothing checks it.

Across 37 controllers that means a contract defect ships silently and surfaces somewhere expensive:

  • a duplicated operationId produces colliding method names in a generated SDK
  • an undeclared path parameter produces a client that cannot call the route
  • a missing 2xx response leaves consumers guessing what success looks like

What this adds

validateOpenApiContract(document, options) — a pure function over a document object, so every rule is testable without booting the application.

Errors — these break consumers

Rule Checks
openapi-version openapi present and 3.x
info-title, info-version Required info fields
paths-present At least one path
operation-id-present Every operation has an operationId
operation-id-unique No two operations share one
responses-documented Operation documents at least one response
success-response At least one 2xx (default does not count)
path-parameter-declared Every {param} has a matching parameter
path-parameter-used Every declared path parameter appears in the template
path-parameter-required Path parameters are never optional
request-body-content A declared request body has content types

Warnings — documentation quality

servers-declared, operation-tagged, tag-declared, tag-used, operation-summary, no-body-on-get, required-response

Opt-in

operation-description, behind --require-descriptions.

Why the severity split matters

Anything that breaks a consumer is an error. Anything that merely degrades documentation is a warning.

That split is what makes this adoptable: it can be wired into CI today without first fixing every missing summary across 37 controllers. Tighten it over time by promoting warnings.

CLI

node dist/openapi/validate-openapi.js openapi.json
node dist/openapi/validate-openapi.js openapi.json --require-response 400 --require-response 500
node dist/openapi/validate-openapi.js openapi.json --require-descriptions

Exit codes: 0 valid, 1 contract errors, 2 usage or parse failure — so it can gate CI directly.

Not wired into CI by default, because it needs a serialised spec and where that gets produced is a repo-level decision. docs/OPENAPI_CONTRACT_VALIDATION.md covers how to serialise the document and the workflow step to add once it is.

Testing

40 tests covering every rule, both severities, the default-is-not-success case, multi-parameter paths, non-HTTP-method path keys, report formatting, and CLI argument parsing.

pnpm --filter api exec jest -- src/openapi/openapi-contract-validator.spec.ts

All passing. eslint apps/api/src/openapi/ clean.

Scope

Four new files, additive only. No existing file is modified, so there is nothing here that can regress current behaviour.

The OpenAPI document is built at runtime from @nestjs/swagger decorators
and served at /api/docs, and nothing checks it. Across 37 controllers a
contract defect — a duplicated operationId, an undeclared path parameter,
a missing 2xx response — ships silently and surfaces as a broken generated
SDK or documentation that does not match the API.

Adds validateOpenApiContract(), a pure function over a document object, so
the rules are testable without booting the application:

- errors (break consumers): openapi-version, info-title, info-version,
  paths-present, operation-id-present, operation-id-unique,
  responses-documented, success-response, path-parameter-declared,
  path-parameter-used, path-parameter-required, request-body-content
- warnings (documentation quality): servers-declared, operation-tagged,
  tag-declared, tag-used, operation-summary, no-body-on-get,
  required-response
- opt-in: operation-description

The severity split is what makes this adoptable — it can gate CI today
without first fixing every missing summary across 37 controllers.

Also adds a CLI (validate-openapi.ts, exit 0/1/2), 40 tests, and docs.

Closes MDTechLabs#1248
@drips-wave

drips-wave Bot commented Sep 29, 2026

Copy link
Copy Markdown

@Cybermaxi7 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Cybermaxi7

Copy link
Copy Markdown
Contributor Author

Heads-up on the red build check — it is not from this PR.

The Lint step fails on unresolved merge conflict markers committed to main:

apps/api/src/dynamic-bridge-discovery/bridge.loader.ts
apps/api/src/real-time-fee-aggregation/bridge.adapters.ts
apps/api/src/real-time-fee-aggregation/fee-aggregation.module.ts
apps/api/src/real-time-fee-aggregation/quotes.controller.ts
apps/api/src/reliability-score/bridge-reliability.service.ts
apps/api/src/reliability-score/reliability-calculator.service.ts

git grep -l '^<<<<<<<' origin/main -- 'apps/api/src/**/*.ts' lists all six on main itself, and each shows in the CI log as Parsing error: Merge conflict marker encountered.

None of the 18 lint errors are in apps/api/src/openapi/; eslint apps/api/src/openapi/ is clean. This PR adds four new files and modifies none, so it cannot affect that job.

Happy to fix those conflict markers in a separate PR if that would help — it looked like it wanted to be its own change rather than something buried in a feature branch.

@mijinummi
mijinummi merged commit c7133ee into MDTechLabs:main Sep 29, 2026
1 check failed
@grantfox-oss grantfox-oss Bot mentioned this pull request Sep 29, 2026
12 tasks
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.

Create OpenAPI contract validation

2 participants