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:
Tim Lai
2020-07-16 17:53:28 -07:00
committed by GitHub
parent b68942c043
commit 2fd1e4037c
15 changed files with 1029 additions and 26 deletions

View File

@@ -9,26 +9,79 @@ export default class Execute extends Component {
operation: PropTypes.object.isRequired,
path: PropTypes.string.isRequired,
method: PropTypes.string.isRequired,
oas3Selectors: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
onExecute: PropTypes.func
}
onClick=()=>{
let { specSelectors, specActions, operation, path, method } = this.props
handleValidateParameters = () => {
let { specSelectors, specActions, path, method } = this.props
specActions.validateParams([path, method])
return specSelectors.validateBeforeExecute([path, method])
}
specActions.validateParams( [path, method] )
if ( specSelectors.validateBeforeExecute([path, method]) ) {
if(this.props.onExecute) {
this.props.onExecute()
}
specActions.execute( { operation, path, method } )
} else {
// deferred by 40ms, to give element class change time to settle.
specActions.clearValidateParams( [path, method] )
setTimeout(() => {
specActions.validateParams([path, method])
}, 40)
handleValidateRequestBody = () => {
let { path, method, specSelectors, oas3Selectors, oas3Actions } = this.props
let validationErrors = {
missingBodyValue: false,
missingRequiredKeys: []
}
// context: reset errors, then (re)validate
oas3Actions.clearRequestBodyValidateError({ path, method })
let oas3RequiredRequestBodyContentType = specSelectors.getOAS3RequiredRequestBodyContentType([path, method])
let oas3RequestBodyValue = oas3Selectors.requestBodyValue(path, method)
let oas3ValidateBeforeExecuteSuccess = oas3Selectors.validateBeforeExecute([path, method])
if (!oas3ValidateBeforeExecuteSuccess) {
validationErrors.missingBodyValue = true
oas3Actions.setRequestBodyValidateError({ path, method, validationErrors })
return false
}
if (!oas3RequiredRequestBodyContentType) {
return true
}
let missingRequiredKeys = oas3Selectors.validateShallowRequired({ oas3RequiredRequestBodyContentType, oas3RequestBodyValue })
if (!missingRequiredKeys || missingRequiredKeys.length < 1) {
return true
}
missingRequiredKeys.forEach((missingKey) => {
validationErrors.missingRequiredKeys.push(missingKey)
})
oas3Actions.setRequestBodyValidateError({ path, method, validationErrors })
return false
}
handleValidationResultPass = () => {
let { specActions, operation, path, method } = this.props
if (this.props.onExecute) {
// loading spinner
this.props.onExecute()
}
specActions.execute({ operation, path, method })
}
handleValidationResultFail = () => {
let { specActions, path, method } = this.props
// deferred by 40ms, to give element class change time to settle.
specActions.clearValidateParams([path, method])
setTimeout(() => {
specActions.validateParams([path, method])
}, 40)
}
handleValidationResult = (isPass) => {
if (isPass) {
this.handleValidationResultPass()
} else {
this.handleValidationResultFail()
}
}
onClick = () => {
let paramsResult = this.handleValidateParameters()
let requestBodyResult = this.handleValidateRequestBody()
let isPass = paramsResult && requestBodyResult
this.handleValidationResult(isPass)
}
onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue([this.props.path, this.props.method], val)

View File

@@ -192,6 +192,8 @@ export default class Operation extends PureComponent {
operation={ operation }
specActions={ specActions }
specSelectors={ specSelectors }
oas3Selectors={ oas3Selectors }
oas3Actions={ oas3Actions }
path={ path }
method={ method }
onExecute={ onExecute } />

View File

@@ -187,6 +187,7 @@ export default class Parameters extends Component {
contentTypes={ requestBody.get("content", List()).keySeq() }
onChange={(value) => {
oas3Actions.setRequestContentType({ value, pathMethod })
oas3Actions.initRequestBodyValidateError({ pathMethod })
}}
className="body-param-content-type" />
</label>
@@ -197,6 +198,7 @@ export default class Parameters extends Component {
requestBody={requestBody}
requestBodyValue={oas3Selectors.requestBodyValue(...pathMethod)}
requestBodyInclusionSetting={oas3Selectors.requestBodyInclusionSetting(...pathMethod)}
requestBodyErrors={oas3Selectors.requestBodyErrors(...pathMethod)}
isExecute={isExecute}
activeExamplesKey={oas3Selectors.activeExamplesMember(
...pathMethod,