open-api
open-api copied to clipboard
validateResponse fails even though response is valid
I am using the vanilla validateAllResponses
from express-openapi and it seems to always throw an error on me when using a response that returns a JSON. Why could that be happening?
Example YAML (OpenAPI 3.0) for that specific path:
/HealthCheck:
get:
operationId: healthCheck
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum:
- OK
validateAllResponses on response "{"status": "OK"}" (without the outer quotation marks, of course) says: "Invalid response for status code 200: should be object". What am I missing? Isn't this a valid object?
that looks correct to me. i'd look at examples in the sample project testing suites.
There is no example that uses this specific validateAllResponses
from the website, and it seems like it doesn't work, since my responses are indeed correct.
Did you manage to resolve this? I am experiencing the same type of issue as you. Validation seems to be failing for arrays that are clearly arrays and objects that are clearly objects. It seems like the validateResponse-function is not working properly.
Edit: I am using promiseMode = true and args.operations, could that play a part in this?
I also had this problem. I think the problem is that the example of validateAllResponses has a bug in it (at least for JSON responses).
If you add a console.log() in it, you'll see that it's called twice. First time for the JSON, second time when the JSON has been stringified, ready to be sent on. At this point it is a string, so fails the validation.
const validateAllResponses = (req, res, next) => {
const strictValidation = req.apiDoc['x-express-openapi-validation-strict']
? true
: false;
if (typeof res.validateResponse === 'function') {
const send = res.send;
res.send = function expressOpenAPISend(...args) {
const onlyWarn = !strictValidation;
if (res.get('x-express-openapi-validation-error-for') !== undefined) {
return send.apply(res, args);
}
const body = args[0];
let validation = res.validateResponse(res.statusCode, body);
let validationMessage;
if (validation === undefined) {
validation = { message: undefined, errors: undefined };
}
if (validation.errors) {
const errorList = Array.from(validation.errors)
.map(_ => _.message)
.join(',');
validationMessage = `Invalid response for status code ${res.statusCode}: ${errorList}`;
console.warn(validationMessage);
// Set to avoid a loop, and to provide the original status code
res.set(
'x-express-openapi-validation-error-for',
res.statusCode.toString(),
);
}
if (onlyWarn || !validation.errors) {
// Restore send. If this is a JSON response it will be converted into a
// string and resent through `res.send`.
res.send = send;
return send.apply(res, args);
} else {
res.status(500);
return res.json({ error: validationMessage });
}
};
}
next();
};
The main difference being restoring res.send
after the first pass.
31,33d30
< // Restore send. If this is a JSON response it will be converted into a
< // string and resent through `res.send`.
< res.send = send;
I don't think this is the main fix however so not put it forward. I don't think this works if you just do res.json({})
but I use res.send({})
exclusively so works fine until I can do some proper digging.
@JasonSome This was asked quite some time ago. But also had this problem and it is because it overwrites the res.send
but not the res.json
. So if you would change all the send
to json
it will work for all json
responses but probably not any send
responses. I changed mine to json, because I just respond with json.
In case someone stumbles on this later on, here is the working version for Json responses:
function validateAllResponses(req: any, res: any, next: any) {
const strictValidation = req.apiDoc['x-express-openapi-validation-strict']
? true
: false;
if (typeof res.validateResponse === 'function') {
const send = res.json;
res.json = function expressOpenAPISend(...args: any[]) {
const onlyWarn = !strictValidation;
if (res.get('x-express-openapi-validation-error-for') !== undefined) {
return send.apply(res, args);
}
const body = args[0];
let validation = res.validateResponse(res.statusCode, body);
let validationMessage;
if (validation === undefined) {
validation = { message: undefined, errors: undefined };
}
if (validation.errors) {
const errorList = Array.from(validation.errors)
.map((_) => _.message)
.join(',');
validationMessage = `Invalid response for status code ${res.statusCode}: ${errorList}`;
// Set to avoid a loop, and to provide the original status code
res.set(
'x-express-openapi-validation-error-for',
res.statusCode.toString()
);
}
if (onlyWarn || !validation.errors) {
return send.apply(res, args);
} else {
res.status(500);
return res.json({ error: validationMessage });
}
};
}
next();
}