Add runtime response header validation with OpenAPI hot-reload#1804
Add runtime response header validation with OpenAPI hot-reload#1804pmcelhaney merged 9 commits intomainfrom
Conversation
pmcelhaney
left a comment
There was a problem hiding this comment.
Make the name of the header "response-type-error". It's okay to have multiple response headers with the same name. Don't append a number.
Done in 9b3a17f. Each error is now reported as a separate |
| ...normalizedResponse, | ||
| headers: { | ||
| ...normalizedResponse.headers, | ||
| "response-type-error": validation.errors, |
There was a problem hiding this comment.
No, one header per error.
|
Try again |
|
@copilot try again |
Done in 5e8278c. The dispatcher now uses |
pmcelhaney
left a comment
There was a problem hiding this comment.
If the OpenAPI file is changed, the changes should be picked up without a restart.
Done in f967106. When the server is running with a local OpenAPI spec file, |
pmcelhaney
left a comment
There was a problem hiding this comment.
Move the file watching code out of app.ts. Put it in a file in the server directory.
Done in f68d9cd. The watching logic now lives in two new files in
|
Summary
Validates response headers at runtime against the OpenAPI spec and reports errors as
response-type-errorHTTP headers — one header per error, with the same name repeated for multiple errors. Enabled by default; disable with--no-validate-response. Changes to the OpenAPI spec file are picked up automatically without a server restart.Manual acceptance tests
response-type-errorheader describes the missing header"not-a-number"for anintegerheader) — verify aresponse-type-errorheader appears with a descriptive messageresponse-type-errorheaders appear (one per error, same header name)response-type-errorheaders appear--no-validate-response— verify noresponse-type-errorheaders appear even when headers are invalidTasks
src/server/response-validator.ts(new) — AJV-based validator: checks required headers are present and header values match their schema types; coerces integer/number/boolean strings before validation; falls back todefaultresponse spec when the specific status code isn't definedsrc/server/registry.ts— AddedappendedHeaders?: [string, string][]toCounterfactResponseObjectto explicitly represent repeated same-name headers as individual entriessrc/server/dispatcher.ts— After normalizing the response, runsvalidateResponsewhenconfig.validateResponses !== false; maps each error to a separate["response-type-error", error]tuple inappendedHeaders— one entry per error, no array bundling under a single keysrc/server/koa-middleware.ts— Iteratesresponse.appendedHeadersand callsctx.res.appendHeaderonce per entry, sending each as a genuinely separate HTTP headersrc/server/config.ts— AddedvalidateResponses: booleanbin/counterfact.js— Added--no-validate-responseflag; wired tovalidateResponsesin the config objectsrc/server/load-openapi-document.ts(new) — ExtractedloadOpenApiDocumentfromapp.tsinto its own server-side module; re-exported fromapp.tsfor backward compatibilitysrc/server/openapi-watcher.ts(new) —OpenApiWatcherclass withwatch()/stopWatching()methods; watches a local OpenAPI spec file with chokidar and updatesdispatcher.openApiDocumenton everychangeevent so validation reflects the latest spec without a restart; skips URL-based specssrc/app.ts— InstantiatesOpenApiWatcherand callswatch()/stopWatching()alongside the other watchers; no longer contains any inline file-watching logictest/server/response-validator.test.ts(15 cases); dispatcher tests updated to assert onappendedHeadersfor required-header missing, wrong type, valid, and disabled scenariosdocs/reference.mdanddocs/faq.mdupdated to document the feature and the new flag