fix(oas3): switching media types should update schema properties (#6518)
* When the media-type is changed, there is a new `onChangeMediaType` method to handle actions. * If target schema properties key/value pairs does NOT equals current schema properties, clear the requestBodyValue, try-it-out request/response and validation params. * If target schema properties key/value pairs DOES equals current schema properties, do not change or re-render schema properties * oas3Selector `validateShallowRequired` now also validates required keys against target media-type Fixes #6201, #6250, #6476
This commit is contained in:
@@ -31,6 +31,7 @@ export default class Execute extends Component {
|
||||
let oas3RequiredRequestBodyContentType = specSelectors.getOAS3RequiredRequestBodyContentType([path, method])
|
||||
let oas3RequestBodyValue = oas3Selectors.requestBodyValue(path, method)
|
||||
let oas3ValidateBeforeExecuteSuccess = oas3Selectors.validateBeforeExecute([path, method])
|
||||
let oas3RequestContentType = oas3Selectors.requestContentType(path, method)
|
||||
|
||||
if (!oas3ValidateBeforeExecuteSuccess) {
|
||||
validationErrors.missingBodyValue = true
|
||||
@@ -40,7 +41,11 @@ export default class Execute extends Component {
|
||||
if (!oas3RequiredRequestBodyContentType) {
|
||||
return true
|
||||
}
|
||||
let missingRequiredKeys = oas3Selectors.validateShallowRequired({ oas3RequiredRequestBodyContentType, oas3RequestBodyValue })
|
||||
let missingRequiredKeys = oas3Selectors.validateShallowRequired({
|
||||
oas3RequiredRequestBodyContentType,
|
||||
oas3RequestContentType,
|
||||
oas3RequestBodyValue
|
||||
})
|
||||
if (!missingRequiredKeys || missingRequiredKeys.length < 1) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -77,6 +77,21 @@ export default class Parameters extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
onChangeMediaType = ( { value, pathMethod } ) => {
|
||||
let { specSelectors, specActions, oas3Selectors, oas3Actions } = this.props
|
||||
let targetMediaType = value
|
||||
let currentMediaType = oas3Selectors.requestContentType(...pathMethod)
|
||||
let schemaPropertiesMatch = specSelectors.isMediaTypeSchemaPropertiesEqual(pathMethod, currentMediaType, targetMediaType)
|
||||
if (!schemaPropertiesMatch) {
|
||||
oas3Actions.clearRequestBodyValue({ pathMethod })
|
||||
specActions.clearResponse(...pathMethod)
|
||||
specActions.clearRequest(...pathMethod)
|
||||
specActions.clearValidateParams(pathMethod)
|
||||
}
|
||||
oas3Actions.setRequestContentType({ value, pathMethod })
|
||||
oas3Actions.initRequestBodyValidateError({ pathMethod })
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
let {
|
||||
@@ -187,8 +202,7 @@ export default class Parameters extends Component {
|
||||
value={oas3Selectors.requestContentType(...pathMethod)}
|
||||
contentTypes={ requestBody.get("content", List()).keySeq() }
|
||||
onChange={(value) => {
|
||||
oas3Actions.setRequestContentType({ value, pathMethod })
|
||||
oas3Actions.initRequestBodyValidateError({ pathMethod })
|
||||
this.onChangeMediaType({ value, pathMethod })
|
||||
}}
|
||||
className="body-param-content-type" />
|
||||
</label>
|
||||
|
||||
@@ -10,6 +10,7 @@ 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 const CLEAR_REQUEST_BODY_VALUE = "oas3_clear_request_body_value"
|
||||
|
||||
export function setSelectedServer (selectedServerUrl, namespace) {
|
||||
return {
|
||||
@@ -80,3 +81,10 @@ export const initRequestBodyValidateError = ({ pathMethod } ) => {
|
||||
payload: { path: pathMethod[0], method: pathMethod[1] }
|
||||
}
|
||||
}
|
||||
|
||||
export const clearRequestBodyValue = ({ pathMethod }) => {
|
||||
return {
|
||||
type: CLEAR_REQUEST_BODY_VALUE,
|
||||
payload: { pathMethod }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
UPDATE_RESPONSE_CONTENT_TYPE,
|
||||
SET_REQUEST_BODY_VALIDATE_ERROR,
|
||||
CLEAR_REQUEST_BODY_VALIDATE_ERROR,
|
||||
CLEAR_REQUEST_BODY_VALUE,
|
||||
} from "./actions"
|
||||
|
||||
export default {
|
||||
@@ -94,4 +95,15 @@ export default {
|
||||
}, bodyValues)
|
||||
})
|
||||
},
|
||||
[CLEAR_REQUEST_BODY_VALUE]: (state, { payload: { pathMethod }}) => {
|
||||
let [path, method] = pathMethod
|
||||
const requestBodyValue = state.getIn(["requestData", path, method, "bodyValue"])
|
||||
if (!requestBodyValue) {
|
||||
return state
|
||||
}
|
||||
if (!Map.isMap(requestBodyValue)) {
|
||||
return state.setIn(["requestData", path, method, "bodyValue"], "")
|
||||
}
|
||||
return state.setIn(["requestData", path, method, "bodyValue"], Map())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,23 +154,23 @@ export const validateBeforeExecute = validateRequestBodyIsRequired(
|
||||
(state, pathMethod) => validateRequestBodyValueExists(state, pathMethod)
|
||||
)
|
||||
|
||||
export const validateShallowRequired = ( state, {oas3RequiredRequestBodyContentType, oas3RequestBodyValue} ) => {
|
||||
export const validateShallowRequired = (state, { oas3RequiredRequestBodyContentType, oas3RequestContentType, oas3RequestBodyValue} ) => {
|
||||
let missingRequiredKeys = []
|
||||
// context: json => String; urlencoded => Map
|
||||
// context: json => String; urlencoded, form-data => 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
|
||||
// Cycle through list of possible contentTypes for matching contentType and defined requiredKeys
|
||||
Object.keys(oas3RequiredRequestBodyContentType.requestContentType).forEach((contentType) => {
|
||||
let contentTypeVal = oas3RequiredRequestBodyContentType.requestContentType[contentType]
|
||||
contentTypeVal.forEach((requiredKey) => {
|
||||
if (requiredKeys.indexOf(requiredKey) < 0 ) {
|
||||
requiredKeys.push(requiredKey)
|
||||
}
|
||||
})
|
||||
if (contentType === oas3RequestContentType) {
|
||||
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"])
|
||||
|
||||
@@ -514,6 +514,17 @@ export const getOAS3RequiredRequestBodyContentType = (state, pathMethod) => {
|
||||
return requiredObj
|
||||
}
|
||||
|
||||
export const isMediaTypeSchemaPropertiesEqual = ( state, pathMethod, currentMediaType, targetMediaType) => {
|
||||
let requestBodyContent = state.getIn(["resolvedSubtrees", "paths", ...pathMethod, "requestBody", "content"], fromJS([]))
|
||||
if (requestBodyContent.size < 2 || !currentMediaType || !targetMediaType) {
|
||||
// nothing to compare
|
||||
return false
|
||||
}
|
||||
let currentMediaTypeSchemaProperties = requestBodyContent.getIn([currentMediaType, "schema", "properties"], fromJS([]))
|
||||
let targetMediaTypeSchemaProperties = requestBodyContent.getIn([targetMediaType, "schema", "properties"], fromJS([]))
|
||||
return currentMediaTypeSchemaProperties.equals(targetMediaTypeSchemaProperties) ? true: false
|
||||
}
|
||||
|
||||
function returnSelfOrNewMap(obj) {
|
||||
// returns obj if obj is an Immutable map, else returns a new Map
|
||||
return Map.isMap(obj) ? obj : new Map()
|
||||
|
||||
Reference in New Issue
Block a user