fix(spec): format validation errors for nested parameters (#9775)
Refs #9774
This commit is contained in:
@@ -491,15 +491,43 @@ export const canExecuteScheme = ( state, path, method ) => {
|
|||||||
|
|
||||||
export const validationErrors = (state, pathMethod) => {
|
export const validationErrors = (state, pathMethod) => {
|
||||||
pathMethod = pathMethod || []
|
pathMethod = pathMethod || []
|
||||||
let paramValues = state.getIn(["meta", "paths", ...pathMethod, "parameters"], fromJS([]))
|
const paramValues = state.getIn(["meta", "paths", ...pathMethod, "parameters"], fromJS([]))
|
||||||
const result = []
|
const result = []
|
||||||
|
|
||||||
paramValues.forEach( (p) => {
|
if (paramValues.length === 0) return result
|
||||||
let errors = p.get("errors")
|
|
||||||
|
const getErrorsWithPaths = (errors, path = []) => {
|
||||||
|
const getNestedErrorsWithPaths = (e, path) => {
|
||||||
|
const currPath = [...path, e.get("propKey") || e.get("index")]
|
||||||
|
return Map.isMap(e.get("error"))
|
||||||
|
? getErrorsWithPaths(e.get("error"), currPath)
|
||||||
|
: { error: e.get("error"), path: currPath }
|
||||||
|
}
|
||||||
|
|
||||||
|
return List.isList(errors)
|
||||||
|
? errors.map((e) => (Map.isMap(e) ? getNestedErrorsWithPaths(e, path) : { error: e, path }))
|
||||||
|
: getNestedErrorsWithPaths(errors, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatError = (error, path, paramName) => {
|
||||||
|
path = path.reduce((acc, curr) => {
|
||||||
|
return typeof curr === "number"
|
||||||
|
? `${acc}[${curr}]`
|
||||||
|
: acc
|
||||||
|
? `${acc}.${curr}`
|
||||||
|
: curr
|
||||||
|
}, "")
|
||||||
|
return `For '${paramName}'${path ? ` at path '${path}'` : ""}: ${error}.`
|
||||||
|
}
|
||||||
|
|
||||||
|
paramValues.forEach( (p, key) => {
|
||||||
|
const paramName = key.split(".").slice(1, -1).join(".")
|
||||||
|
const errors = p.get("errors")
|
||||||
if (errors && errors.count()) {
|
if (errors && errors.count()) {
|
||||||
errors
|
const errorsWithPaths = getErrorsWithPaths(errors)
|
||||||
.map((e) => (Map.isMap(e) ? `${e.get("propKey")}: ${e.get("error")}` : e))
|
errorsWithPaths.forEach(({error, path}) => {
|
||||||
.forEach((e) => result.push(e))
|
result.push(formatError(error, path, paramName))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -1388,7 +1388,7 @@ describe("validationErrors", function() {
|
|||||||
"/": {
|
"/": {
|
||||||
get: {
|
get: {
|
||||||
parameters: {
|
parameters: {
|
||||||
id: {
|
"query.id.hash": {
|
||||||
errors: [
|
errors: [
|
||||||
"Value must be an integer"
|
"Value must be an integer"
|
||||||
]
|
]
|
||||||
@@ -1397,7 +1397,7 @@ describe("validationErrors", function() {
|
|||||||
},
|
},
|
||||||
post: {
|
post: {
|
||||||
parameters: {
|
parameters: {
|
||||||
body: {
|
"query.with.dot.hash": {
|
||||||
errors: [
|
errors: [
|
||||||
{
|
{
|
||||||
error: "Value must be an integer",
|
error: "Value must be an integer",
|
||||||
@@ -1411,25 +1411,85 @@ describe("validationErrors", function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/nested": {
|
||||||
|
post: {
|
||||||
|
parameters: {
|
||||||
|
"query.arrayWithObjects.hash": {
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
error: "Parameter string value must be valid JSON",
|
||||||
|
index: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
error: {
|
||||||
|
error: "Value must be a string",
|
||||||
|
propKey: "name"
|
||||||
|
},
|
||||||
|
index: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"query.objectWithArray.hash": {
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
error: {
|
||||||
|
error: {
|
||||||
|
error: "Value must be a number",
|
||||||
|
propKey: "b",
|
||||||
|
},
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
propKey: "a",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"query.objectWithoutArray.hash": {
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
error: {
|
||||||
|
error: {
|
||||||
|
error: "Value must be a string",
|
||||||
|
propKey: "e",
|
||||||
|
},
|
||||||
|
propKey: "d",
|
||||||
|
},
|
||||||
|
propKey: "c",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should return validation errors without formatting them", function () {
|
it("should return validation errors with parameter name", function () {
|
||||||
const result = validationErrors(state, ["/", "get"])
|
const result = validationErrors(state, ["/", "get"])
|
||||||
|
|
||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
"Value must be an integer"
|
"For 'id': Value must be an integer."
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should return formatted validation errors", function () {
|
it("should return validation errors with parameter name and path", function () {
|
||||||
const result = validationErrors(state, ["/", "post"])
|
const result = validationErrors(state, ["/", "post"])
|
||||||
|
|
||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
"id: Value must be an integer",
|
"For 'with.dot' at path 'id': Value must be an integer.",
|
||||||
"name: Value must be a string"
|
"For 'with.dot' at path 'name': Value must be a string."
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should return validation errors with parameter name and path for nested parameters", function () {
|
||||||
|
const result = validationErrors(state, ["/nested", "post"])
|
||||||
|
|
||||||
|
expect(result).toEqual([
|
||||||
|
"For 'arrayWithObjects' at path '[0]': Parameter string value must be valid JSON.",
|
||||||
|
"For 'arrayWithObjects' at path '[1].name': Value must be a string.",
|
||||||
|
"For 'objectWithArray' at path 'a[0].b': Value must be a number.",
|
||||||
|
"For 'objectWithoutArray' at path 'c.d.e': Value must be a string."
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user