mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-14 00:19:16 +01:00
Chore: remove "dataPath" from data OpenAPI data errors. (#5272)
The `dataPath` was present (but not in the type) in previous versions of the error library that we use. But with the recent major upgrade, it's been removed and the `instancePath` property has finally come into use. This PR removes all the handling for the previous property and replaces it with `instancePath`. Because the `dataPath` used full stops and the `instancePath` uses slashes, we need to change a little bit of the handling too.
This commit is contained in:
parent
92e2b1890c
commit
b3054c9277
@ -38,7 +38,7 @@ class BadDataError extends UnleashError {
|
|||||||
export default BadDataError;
|
export default BadDataError;
|
||||||
|
|
||||||
const constructPath = (pathToParent: string, propertyName: string) =>
|
const constructPath = (pathToParent: string, propertyName: string) =>
|
||||||
[pathToParent, propertyName].filter(Boolean).join('.');
|
[pathToParent, propertyName].filter(Boolean).join('/');
|
||||||
|
|
||||||
const missingRequiredPropertyMessage = (
|
const missingRequiredPropertyMessage = (
|
||||||
pathToParentObject: string,
|
pathToParentObject: string,
|
||||||
@ -74,10 +74,10 @@ const genericErrorMessage = (
|
|||||||
propertyName: string,
|
propertyName: string,
|
||||||
errorMessage: string = 'is invalid',
|
errorMessage: string = 'is invalid',
|
||||||
) => {
|
) => {
|
||||||
const input = getProp(requestBody, propertyName);
|
const input = getProp(requestBody, propertyName.split('/'));
|
||||||
|
|
||||||
const youSent = JSON.stringify(input);
|
const youSent = JSON.stringify(input);
|
||||||
const description = `The \`.${propertyName}\` property ${errorMessage}. You sent ${youSent}.`;
|
const description = `The \`${propertyName}\` property ${errorMessage}. You sent ${youSent}.`;
|
||||||
return {
|
return {
|
||||||
description,
|
description,
|
||||||
message: description,
|
message: description,
|
||||||
@ -122,16 +122,11 @@ const enumMessage = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sometimes, the error object contains a dataPath, even if it's not
|
|
||||||
type ActualErrorObject = ErrorObject & { dataPath?: string };
|
|
||||||
|
|
||||||
export const fromOpenApiValidationError =
|
export const fromOpenApiValidationError =
|
||||||
(requestBody: object) =>
|
(requestBody: object) =>
|
||||||
(validationError: ActualErrorObject): ValidationErrorDescription => {
|
(validationError: ErrorObject): ValidationErrorDescription => {
|
||||||
const { instancePath, params, message, dataPath } = validationError;
|
const { instancePath, params, message } = validationError;
|
||||||
const propertyName =
|
const propertyName = instancePath.substring('/body/'.length);
|
||||||
dataPath?.substring('.body.'.length) ??
|
|
||||||
instancePath.substring('/body/'.length);
|
|
||||||
|
|
||||||
switch (validationError.keyword) {
|
switch (validationError.keyword) {
|
||||||
case 'required':
|
case 'required':
|
||||||
|
@ -50,8 +50,7 @@ describe('OpenAPI error conversion', () => {
|
|||||||
it('Gives useful error messages for missing properties', () => {
|
it('Gives useful error messages for missing properties', () => {
|
||||||
const error = {
|
const error = {
|
||||||
keyword: 'required',
|
keyword: 'required',
|
||||||
instancePath: '',
|
instancePath: '/body',
|
||||||
dataPath: '.body',
|
|
||||||
schemaPath: '#/components/schemas/addonCreateUpdateSchema/required',
|
schemaPath: '#/components/schemas/addonCreateUpdateSchema/required',
|
||||||
params: {
|
params: {
|
||||||
missingProperty: 'enabled',
|
missingProperty: 'enabled',
|
||||||
@ -75,8 +74,7 @@ describe('OpenAPI error conversion', () => {
|
|||||||
it('Gives useful error messages for type errors', () => {
|
it('Gives useful error messages for type errors', () => {
|
||||||
const error = {
|
const error = {
|
||||||
keyword: 'type',
|
keyword: 'type',
|
||||||
instancePath: '',
|
instancePath: '/body/parameters',
|
||||||
dataPath: '.body.parameters',
|
|
||||||
schemaPath:
|
schemaPath:
|
||||||
'#/components/schemas/addonCreateUpdateSchema/properties/parameters/type',
|
'#/components/schemas/addonCreateUpdateSchema/properties/parameters/type',
|
||||||
params: {
|
params: {
|
||||||
@ -101,13 +99,12 @@ describe('OpenAPI error conversion', () => {
|
|||||||
expect(result.description).toContain(JSON.stringify(parameterValue));
|
expect(result.description).toContain(JSON.stringify(parameterValue));
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each(['.body', '.body.subObject'])(
|
it.each(['/body', '/body/subObject'])(
|
||||||
'Gives useful error messages for oneOf errors in %s',
|
'Gives useful error messages for oneOf errors in %s',
|
||||||
(dataPath) => {
|
(instancePath) => {
|
||||||
const error = {
|
const error = {
|
||||||
keyword: 'oneOf',
|
keyword: 'oneOf',
|
||||||
instancePath: '',
|
instancePath,
|
||||||
dataPath,
|
|
||||||
schemaPath: '#/components/schemas/createApiTokenSchema/oneOf',
|
schemaPath: '#/components/schemas/createApiTokenSchema/oneOf',
|
||||||
params: {
|
params: {
|
||||||
passingSchemas: null,
|
passingSchemas: null,
|
||||||
@ -125,7 +122,7 @@ describe('OpenAPI error conversion', () => {
|
|||||||
description:
|
description:
|
||||||
// it provides the message
|
// it provides the message
|
||||||
expect.stringContaining(error.message),
|
expect.stringContaining(error.message),
|
||||||
path: dataPath.substring('.body.'.length),
|
path: instancePath.substring('/body/'.length),
|
||||||
});
|
});
|
||||||
|
|
||||||
// it tells the user what happened
|
// it tells the user what happened
|
||||||
@ -134,18 +131,17 @@ describe('OpenAPI error conversion', () => {
|
|||||||
);
|
);
|
||||||
// it tells the user what part of the request body this pertains to
|
// it tells the user what part of the request body this pertains to
|
||||||
expect(result.description).toContain(
|
expect(result.description).toContain(
|
||||||
dataPath === '.body'
|
instancePath === '/body'
|
||||||
? 'root object'
|
? 'root object'
|
||||||
: `"${dataPath.substring('.body.'.length)}" property`,
|
: `"${instancePath.substring('/body/'.length)}" property`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it('Gives useful pattern error messages', () => {
|
it('Gives useful pattern error messages', () => {
|
||||||
const error = {
|
const error = {
|
||||||
instancePath: '',
|
|
||||||
keyword: 'pattern',
|
keyword: 'pattern',
|
||||||
dataPath: '.body.description',
|
instancePath: '/body/description',
|
||||||
schemaPath:
|
schemaPath:
|
||||||
'#/components/schemas/addonCreateUpdateSchema/properties/description/pattern',
|
'#/components/schemas/addonCreateUpdateSchema/properties/description/pattern',
|
||||||
params: {
|
params: {
|
||||||
@ -199,9 +195,8 @@ describe('OpenAPI error conversion', () => {
|
|||||||
|
|
||||||
it('Gives useful min/maxlength error messages', () => {
|
it('Gives useful min/maxlength error messages', () => {
|
||||||
const error = {
|
const error = {
|
||||||
instancePath: '',
|
|
||||||
keyword: 'maxLength',
|
keyword: 'maxLength',
|
||||||
dataPath: '.body.description',
|
instancePath: '/body/description',
|
||||||
schemaPath:
|
schemaPath:
|
||||||
'#/components/schemas/addonCreateUpdateSchema/properties/description/maxLength',
|
'#/components/schemas/addonCreateUpdateSchema/properties/description/maxLength',
|
||||||
params: {
|
params: {
|
||||||
@ -230,8 +225,7 @@ describe('OpenAPI error conversion', () => {
|
|||||||
it('Handles numerical min/max errors', () => {
|
it('Handles numerical min/max errors', () => {
|
||||||
const error = {
|
const error = {
|
||||||
keyword: 'maximum',
|
keyword: 'maximum',
|
||||||
instancePath: '',
|
instancePath: '/body/newprop',
|
||||||
dataPath: '.body.newprop',
|
|
||||||
schemaPath:
|
schemaPath:
|
||||||
'#/components/schemas/addonCreateUpdateSchema/properties/newprop/maximum',
|
'#/components/schemas/addonCreateUpdateSchema/properties/newprop/maximum',
|
||||||
params: {
|
params: {
|
||||||
@ -265,9 +259,7 @@ describe('OpenAPI error conversion', () => {
|
|||||||
const errors: [ErrorObject, ...ErrorObject[]] = [
|
const errors: [ErrorObject, ...ErrorObject[]] = [
|
||||||
{
|
{
|
||||||
keyword: 'maximum',
|
keyword: 'maximum',
|
||||||
instancePath: '',
|
instancePath: '/body/newprop',
|
||||||
// @ts-expect-error
|
|
||||||
dataPath: '.body.newprop',
|
|
||||||
schemaPath:
|
schemaPath:
|
||||||
'#/components/schemas/addonCreateUpdateSchema/properties/newprop/maximum',
|
'#/components/schemas/addonCreateUpdateSchema/properties/newprop/maximum',
|
||||||
params: {
|
params: {
|
||||||
@ -279,8 +271,7 @@ describe('OpenAPI error conversion', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
keyword: 'required',
|
keyword: 'required',
|
||||||
instancePath: '',
|
instancePath: '/body',
|
||||||
dataPath: '.body',
|
|
||||||
schemaPath:
|
schemaPath:
|
||||||
'#/components/schemas/addonCreateUpdateSchema/required',
|
'#/components/schemas/addonCreateUpdateSchema/required',
|
||||||
params: {
|
params: {
|
||||||
@ -312,8 +303,7 @@ describe('OpenAPI error conversion', () => {
|
|||||||
it('gives useful messages for base-level properties', () => {
|
it('gives useful messages for base-level properties', () => {
|
||||||
const openApiError = {
|
const openApiError = {
|
||||||
keyword: 'additionalProperties',
|
keyword: 'additionalProperties',
|
||||||
instancePath: '',
|
instancePath: '/body',
|
||||||
dataPath: '.body',
|
|
||||||
schemaPath:
|
schemaPath:
|
||||||
'#/components/schemas/addonCreateUpdateSchema/additionalProperties',
|
'#/components/schemas/addonCreateUpdateSchema/additionalProperties',
|
||||||
params: { additionalProperty: 'bogus' },
|
params: { additionalProperty: 'bogus' },
|
||||||
@ -343,8 +333,7 @@ describe('OpenAPI error conversion', () => {
|
|||||||
};
|
};
|
||||||
const openApiError = {
|
const openApiError = {
|
||||||
keyword: 'additionalProperties',
|
keyword: 'additionalProperties',
|
||||||
instancePath: '',
|
instancePath: '/body/nestedObject/nested2',
|
||||||
dataPath: '.body.nestedObject.nested2',
|
|
||||||
schemaPath:
|
schemaPath:
|
||||||
'#/components/schemas/addonCreateUpdateSchema/properties/nestedObject/properties/nested2/additionalProperties',
|
'#/components/schemas/addonCreateUpdateSchema/properties/nestedObject/properties/nested2/additionalProperties',
|
||||||
params: { additionalProperty: 'extraPropertyName' },
|
params: { additionalProperty: 'extraPropertyName' },
|
||||||
@ -354,8 +343,8 @@ describe('OpenAPI error conversion', () => {
|
|||||||
const error = fromOpenApiValidationError(request2)(openApiError);
|
const error = fromOpenApiValidationError(request2)(openApiError);
|
||||||
|
|
||||||
expect(error).toMatchObject({
|
expect(error).toMatchObject({
|
||||||
description: expect.stringContaining('nestedObject.nested2'),
|
description: expect.stringContaining('nestedObject/nested2'),
|
||||||
path: 'nestedObject.nested2.extraPropertyName',
|
path: 'nestedObject/nested2/extraPropertyName',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(error.description).toContain(
|
expect(error.description).toContain(
|
||||||
@ -368,12 +357,11 @@ describe('OpenAPI error conversion', () => {
|
|||||||
it('Handles deeply nested properties gracefully', () => {
|
it('Handles deeply nested properties gracefully', () => {
|
||||||
const error = {
|
const error = {
|
||||||
keyword: 'type',
|
keyword: 'type',
|
||||||
dataPath: '.body.nestedObject.a.b',
|
instancePath: '/body/nestedObject/a/b',
|
||||||
schemaPath:
|
schemaPath:
|
||||||
'#/components/schemas/addonCreateUpdateSchema/properties/nestedObject/properties/a/properties/b/type',
|
'#/components/schemas/addonCreateUpdateSchema/properties/nestedObject/properties/a/properties/b/type',
|
||||||
params: { type: 'string' },
|
params: { type: 'string' },
|
||||||
message: 'should be string',
|
message: 'should be string',
|
||||||
instancePath: '',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = fromOpenApiValidationError({
|
const result = fromOpenApiValidationError({
|
||||||
@ -381,8 +369,8 @@ describe('OpenAPI error conversion', () => {
|
|||||||
})(error);
|
})(error);
|
||||||
|
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
description: expect.stringMatching(/\bnestedObject.a.b\b/),
|
description: expect.stringMatching(/\bnestedObject\/a\/b\b/),
|
||||||
path: 'nestedObject.a.b',
|
path: 'nestedObject/a/b',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.description).toContain('[]');
|
expect(result.description).toContain('[]');
|
||||||
@ -391,11 +379,10 @@ describe('OpenAPI error conversion', () => {
|
|||||||
it('Handles deeply nested properties on referenced schemas', () => {
|
it('Handles deeply nested properties on referenced schemas', () => {
|
||||||
const error = {
|
const error = {
|
||||||
keyword: 'type',
|
keyword: 'type',
|
||||||
dataPath: '.body.nestedObject.a.b',
|
instancePath: '/body/nestedObject/a/b',
|
||||||
schemaPath: '#/components/schemas/parametersSchema/type',
|
schemaPath: '#/components/schemas/parametersSchema/type',
|
||||||
params: { type: 'object' },
|
params: { type: 'object' },
|
||||||
message: 'should be object',
|
message: 'should be object',
|
||||||
instancePath: '',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const illegalValue = 'illegal string';
|
const illegalValue = 'illegal string';
|
||||||
@ -405,10 +392,10 @@ describe('OpenAPI error conversion', () => {
|
|||||||
|
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
description: expect.stringContaining(illegalValue),
|
description: expect.stringContaining(illegalValue),
|
||||||
path: 'nestedObject.a.b',
|
path: 'nestedObject/a/b',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.description).toMatch(/\bnestedObject.a.b\b/);
|
expect(result.description).toMatch(/\bnestedObject\/a\/b\b/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user