Skip to content

Commit

Permalink
fix(spec): format validation errors for nested parameters (#9775)
Browse files Browse the repository at this point in the history
Refs #9774
  • Loading branch information
glowcloud authored Apr 10, 2024
1 parent 3b72ee1 commit 0f395c2
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 13 deletions.
40 changes: 34 additions & 6 deletions src/core/plugins/spec/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -491,15 +491,43 @@ export const canExecuteScheme = ( state, path, method ) => {

export const validationErrors = (state, pathMethod) => {
pathMethod = pathMethod || []
let paramValues = state.getIn(["meta", "paths", ...pathMethod, "parameters"], fromJS([]))
const paramValues = state.getIn(["meta", "paths", ...pathMethod, "parameters"], fromJS([]))
const result = []

paramValues.forEach( (p) => {
let errors = p.get("errors")
if (paramValues.length === 0) return result

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()) {
errors
.map((e) => (Map.isMap(e) ? `${e.get("propKey")}: ${e.get("error")}` : e))
.forEach((e) => result.push(e))
const errorsWithPaths = getErrorsWithPaths(errors)
errorsWithPaths.forEach(({error, path}) => {
result.push(formatError(error, path, paramName))
})
}
})
return result
Expand Down
74 changes: 67 additions & 7 deletions test/unit/core/plugins/spec/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1388,7 +1388,7 @@ describe("validationErrors", function() {
"/": {
get: {
parameters: {
id: {
"query.id.hash": {
errors: [
"Value must be an integer"
]
Expand All @@ -1397,7 +1397,7 @@ describe("validationErrors", function() {
},
post: {
parameters: {
body: {
"query.with.dot.hash": {
errors: [
{
error: "Value must be an integer",
Expand All @@ -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"])

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"])

expect(result).toEqual([
"id: Value must be an integer",
"name: Value must be a string"
"For 'with.dot' at path 'id': Value must be an integer.",
"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."
])
})
})

0 comments on commit 0f395c2

Please sign in to comment.