in functions/error-response.js [22:135]
function validateErrorResponseSchema(errorResponseSchema, pathToSchema) {
const errors = [];
// The error response MUST be a single JSON object.
if (!errorResponseSchema.properties) {
errors.push({
message: 'Error response schema must be an object schema.',
path: pathToSchema,
});
return errors;
}
// This object MUST have a name/value pair named "error." The value MUST be a JSON object.
if (!errorResponseSchema.properties.error || !errorResponseSchema.properties.error.properties) {
errors.push({
message: 'Error response schema should contain an object property named `error`.',
path: [...pathToSchema, 'properties', 'error'],
});
return errors;
}
// The `error` object should be required (always present)
if (!errorResponseSchema.required?.includes?.('error')) {
errors.push({
message: 'The `error` property in the error response schema should be required.',
path: [...pathToSchema, 'required'],
});
}
const errorSchema = errorResponseSchema.properties.error;
const pathToErrorSchema = [...pathToSchema, 'properties', 'error'];
// Spectral message dedup will drop all but first message with the same path, so we need
// combine messages when they would wind up with the same path.
const hasCode = !!errorSchema.properties.code;
const hasMessage = !!errorSchema.properties.message;
if (!hasCode && hasMessage) {
errors.push({
message: 'Error schema should contain `code` property.',
path: [...pathToErrorSchema, 'properties'],
});
} else if (hasCode && !hasMessage) {
errors.push({
message: 'Error schema should contain `message` property.',
path: [...pathToErrorSchema, 'properties'],
});
} else if (!hasCode && !hasMessage) {
errors.push({
message: 'Error schema should contain `code` and `message` properties.',
path: [...pathToErrorSchema, 'properties'],
});
}
if (hasCode && errorSchema.properties.code.type !== 'string') {
errors.push({
message: 'The `code` property of error schema should be type `string`.',
path: [...pathToErrorSchema, 'properties', 'code', 'type'],
});
}
if (hasMessage && errorSchema.properties.message.type !== 'string') {
errors.push({
message: 'The `message` property of error schema should be type `string`.',
path: [...pathToErrorSchema, 'properties', 'message', 'type'],
});
}
// Check if schema defines `code` and `message` as required
if (['code', 'message'].every((prop) => !errorSchema.required?.includes?.(prop))) {
// Either there is no required or it is missing both properties, so report both missing
errors.push({
message: 'Error schema should define `code` and `message` properties as required.',
path: [...pathToErrorSchema, 'required'],
});
} else if (!errorSchema.required.includes('code')) {
errors.push({
message: 'Error schema should define `code` property as required.',
path: [...pathToErrorSchema, 'required'],
});
} else if (!errorSchema.required.includes('message')) {
errors.push({
message: 'Error schema should define `message` property as required.',
path: [...pathToErrorSchema, 'required'],
});
}
// The value for the "target" name/value pair is ... the name of the property in error
if (!!errorSchema.properties.target && errorSchema.properties.target.type !== 'string') {
errors.push({
message: 'The `target` property of the error schema should be type `string`.',
path: [...pathToErrorSchema, 'properties', 'target'],
});
}
// The value for the "details" name/value pair MUST be an array of JSON objects
if (!!errorSchema.properties.details && !isArraySchema(errorSchema.properties.details)) {
errors.push({
message: 'The `details` property of the error schema should be an array.',
path: [...pathToErrorSchema, 'properties', 'details'],
});
}
// The value for the "innererror" name/value pair MUST be an object
if (!!errorSchema.properties.innererror && !isObjectSchema(errorSchema.properties.innererror)) {
errors.push({
message: 'The `innererror` property of the error schema should be an object.',
path: [...pathToErrorSchema, 'properties', 'innererror'],
});
}
return errors;
}