feat(RequestBody): validation support for required fields (#6223)
fixes #5181 * application/json * application/xml * application/x-www-form-urlencoded * Set requestBodyValue values to be an immutable Map, as "value". Previously stored as a normal String. * This enables adding "errors" to the Map, for validation use * note: getOAS3RequiredRequestBodyContentType requires state.spec, * which is not available to state.oas3
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { OrderedMap, Map } from "immutable"
|
||||
import { isOAS3 as isOAS3Helper } from "./helpers"
|
||||
|
||||
|
||||
// Helpers
|
||||
|
||||
function onlyOAS3(selector) {
|
||||
@@ -15,6 +14,35 @@ function onlyOAS3(selector) {
|
||||
}
|
||||
}
|
||||
|
||||
function validateRequestBodyIsRequired(selector) {
|
||||
return (...args) => (system) => {
|
||||
const specJson = system.getSystem().specSelectors.specJson()
|
||||
const argsList = [...args]
|
||||
// expect argsList[0] = state
|
||||
let pathMethod = argsList[1] || []
|
||||
let isOas3RequestBodyRequired = specJson.getIn(["paths", ...pathMethod, "requestBody", "required"])
|
||||
|
||||
if (isOas3RequestBodyRequired) {
|
||||
return selector(...args)
|
||||
} else {
|
||||
// validation pass b/c not required
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const validateRequestBodyValueExists = (state, pathMethod) => {
|
||||
pathMethod = pathMethod || []
|
||||
let oas3RequestBodyValue = state.getIn(["requestData", ...pathMethod, "bodyValue"])
|
||||
// context: bodyValue can be a String, or a Map
|
||||
if (!oas3RequestBodyValue) {
|
||||
return false
|
||||
}
|
||||
// validation pass if String is not empty, or if Map exists
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
export const selectedServer = onlyOAS3((state, namespace) => {
|
||||
const path = namespace ? [namespace, "selectedServer"] : ["selectedServer"]
|
||||
return state.getIn(path) || ""
|
||||
@@ -31,6 +59,11 @@ export const requestBodyInclusionSetting = onlyOAS3((state, path, method) => {
|
||||
}
|
||||
)
|
||||
|
||||
export const requestBodyErrors = onlyOAS3((state, path, method) => {
|
||||
return state.getIn(["requestData", path, method, "errors"]) || null
|
||||
}
|
||||
)
|
||||
|
||||
export const activeExamplesMember = onlyOAS3((state, path, method, type, name) => {
|
||||
return state.getIn(["examples", path, method, type, name, "activeExample"]) || null
|
||||
}
|
||||
@@ -116,3 +149,34 @@ export const serverEffectiveValue = onlyOAS3((state, locationData) => {
|
||||
return str
|
||||
}
|
||||
)
|
||||
|
||||
export const validateBeforeExecute = validateRequestBodyIsRequired(
|
||||
(state, pathMethod) => validateRequestBodyValueExists(state, pathMethod)
|
||||
)
|
||||
|
||||
export const validateShallowRequired = ( state, {oas3RequiredRequestBodyContentType, oas3RequestBodyValue} ) => {
|
||||
let missingRequiredKeys = []
|
||||
// context: json => String; urlencoded => Map
|
||||
if (!Map.isMap(oas3RequestBodyValue)) {
|
||||
return missingRequiredKeys
|
||||
}
|
||||
let requiredKeys = []
|
||||
// We intentionally cycle through list of contentTypes for defined requiredKeys
|
||||
// instead of assuming first contentType will accurately list all expected requiredKeys
|
||||
// Alternatively, we could try retrieving the contentType first, and match exactly. This would be a more accurate representation of definition
|
||||
Object.keys(oas3RequiredRequestBodyContentType.requestContentType).forEach((contentType) => {
|
||||
let contentTypeVal = oas3RequiredRequestBodyContentType.requestContentType[contentType]
|
||||
contentTypeVal.forEach((requiredKey) => {
|
||||
if (requiredKeys.indexOf(requiredKey) < 0 ) {
|
||||
requiredKeys.push(requiredKey)
|
||||
}
|
||||
})
|
||||
})
|
||||
requiredKeys.forEach((key) => {
|
||||
let requiredKeyValue = oas3RequestBodyValue.getIn([key, "value"])
|
||||
if (!requiredKeyValue) {
|
||||
missingRequiredKeys.push(key)
|
||||
}
|
||||
})
|
||||
return missingRequiredKeys
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user