diff --git a/src/core/components/execute.jsx b/src/core/components/execute.jsx index d9e8b4f462f..0c005fcbbb4 100644 --- a/src/core/components/execute.jsx +++ b/src/core/components/execute.jsx @@ -9,28 +9,81 @@ 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]) + } + + 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 + } - specActions.validateParams( [path, method] ) + handleValidationResultPass = () => { + let { specActions, operation, path, method } = this.props + if (this.props.onExecute) { + // loading spinner + this.props.onExecute() + } + specActions.execute({ operation, path, method }) + } - if ( specSelectors.validateBeforeExecute([path, method]) ) { - if(this.props.onExecute) { - 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 { - // deferred by 40ms, to give element class change time to settle. - specActions.clearValidateParams( [path, method] ) - setTimeout(() => { - specActions.validateParams([path, method]) - }, 40) + 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) render(){ diff --git a/src/core/components/operation.jsx b/src/core/components/operation.jsx index 29130be2a90..a4a799772ff 100644 --- a/src/core/components/operation.jsx +++ b/src/core/components/operation.jsx @@ -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 } /> diff --git a/src/core/components/parameters/parameters.jsx b/src/core/components/parameters/parameters.jsx index 0f574b32622..49929e817de 100644 --- a/src/core/components/parameters/parameters.jsx +++ b/src/core/components/parameters/parameters.jsx @@ -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" /> @@ -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, diff --git a/src/core/plugins/oas3/actions.js b/src/core/plugins/oas3/actions.js index 0736489a00b..ef6a7ae6b9b 100644 --- a/src/core/plugins/oas3/actions.js +++ b/src/core/plugins/oas3/actions.js @@ -8,6 +8,8 @@ export const UPDATE_ACTIVE_EXAMPLES_MEMBER = "oas3_set_active_examples_member" export const UPDATE_REQUEST_CONTENT_TYPE = "oas3_set_request_content_type" export const UPDATE_RESPONSE_CONTENT_TYPE = "oas3_set_response_content_type" export const UPDATE_SERVER_VARIABLE_VALUE = "oas3_set_server_variable_value" +export const SET_REQUEST_BODY_VALIDATE_ERROR = "oas3_set_request_body_validate_error" +export const CLEAR_REQUEST_BODY_VALIDATE_ERROR = "oas3_clear_request_body_validate_error" export function setSelectedServer (selectedServerUrl, namespace) { return { @@ -57,3 +59,24 @@ export function setServerVariableValue ({ server, namespace, key, val }) { payload: { server, namespace, key, val } } } + +export const setRequestBodyValidateError = ({ path, method, validationErrors }) => { + return { + type: SET_REQUEST_BODY_VALIDATE_ERROR, + payload: { path, method, validationErrors } + } +} + +export const clearRequestBodyValidateError = ({ path, method }) => { + return { + type: CLEAR_REQUEST_BODY_VALIDATE_ERROR, + payload: { path, method } + } +} + +export const initRequestBodyValidateError = ({ pathMethod } ) => { + return { + type: CLEAR_REQUEST_BODY_VALIDATE_ERROR, + payload: { path: pathMethod[0], method: pathMethod[1] } + } +} diff --git a/src/core/plugins/oas3/components/request-body-editor.jsx b/src/core/plugins/oas3/components/request-body-editor.jsx index 6d6d09d2d77..ea729ba564e 100644 --- a/src/core/plugins/oas3/components/request-body-editor.jsx +++ b/src/core/plugins/oas3/components/request-body-editor.jsx @@ -1,5 +1,6 @@ import React, { PureComponent } from "react" import PropTypes from "prop-types" +import cx from "classnames" import { stringify } from "core/utils" const NOOP = Function.prototype @@ -11,6 +12,7 @@ export default class RequestBodyEditor extends PureComponent { getComponent: PropTypes.func.isRequired, value: PropTypes.string, defaultValue: PropTypes.string, + errors: PropTypes.array, }; static defaultProps = { @@ -74,19 +76,22 @@ export default class RequestBodyEditor extends PureComponent { render() { let { - getComponent + getComponent, + errors } = this.props let { value } = this.state + let isInvalid = errors.size > 0 ? true : false const TextArea = getComponent("TextArea") return (