diff --git a/src/core/components/operation.jsx b/src/core/components/operation.jsx index c7a6b194ff8..14f2122758a 100644 --- a/src/core/components/operation.jsx +++ b/src/core/components/operation.jsx @@ -248,7 +248,7 @@ export default class Operation extends PureComponent { oas3Actions={oas3Actions} specActions={ specActions } produces={ produces } - producesValue={ operation.get("produces_value") } + producesValue={ specSelectors.currentProducesFor([path, method]) } specPath={specPath.push("responses")} path={ path } method={ method } diff --git a/src/core/containers/OperationContainer.jsx b/src/core/containers/OperationContainer.jsx index dae2b735fae..6364365af7a 100644 --- a/src/core/containers/OperationContainer.jsx +++ b/src/core/containers/OperationContainer.jsx @@ -82,27 +82,9 @@ export default class OperationContainer extends PureComponent { } componentWillReceiveProps(nextProps) { - const defaultContentType = "application/json" - let { specActions, path, method, op } = nextProps - let operation = op.get("operation") - let producesValue = operation.get("produces_value") - let produces = operation.get("produces") - let consumes = operation.get("consumes") - let consumesValue = operation.get("consumes_value") - if(nextProps.response !== this.props.response) { this.setState({ executeInProgress: false }) } - - if (producesValue === undefined) { - producesValue = produces && produces.size ? produces.first() : defaultContentType - specActions.changeProducesValue([path, method], producesValue) - } - - if (consumesValue === undefined) { - consumesValue = consumes && consumes.size ? consumes.first() : defaultContentType - specActions.changeConsumesValue([path, method], consumesValue) - } } toggleShown =() => { diff --git a/src/core/plugins/spec/actions.js b/src/core/plugins/spec/actions.js index a0cf3588308..0d0d853a0e3 100644 --- a/src/core/plugins/spec/actions.js +++ b/src/core/plugins/spec/actions.js @@ -19,7 +19,7 @@ export const LOG_REQUEST = "spec_log_request" export const CLEAR_RESPONSE = "spec_clear_response" export const CLEAR_REQUEST = "spec_clear_request" export const CLEAR_VALIDATE_PARAMS = "spec_clear_validate_param" -export const UPDATE_OPERATION_VALUE = "spec_update_operation_value" +export const UPDATE_OPERATION_META_VALUE = "spec_update_operation_meta_value" export const UPDATE_RESOLVED = "spec_update_resolved" export const SET_SCHEME = "set_scheme" @@ -150,14 +150,14 @@ export function clearValidateParams( payload ){ export function changeConsumesValue(path, value) { return { - type: UPDATE_OPERATION_VALUE, + type: UPDATE_OPERATION_META_VALUE, payload:{ path, value, key: "consumes_value" } } } export function changeProducesValue(path, value) { return { - type: UPDATE_OPERATION_VALUE, + type: UPDATE_OPERATION_META_VALUE, payload:{ path, value, key: "produces_value" } } } diff --git a/src/core/plugins/spec/reducers.js b/src/core/plugins/spec/reducers.js index 0f8020bf0ef..bf8dadf5e33 100644 --- a/src/core/plugins/spec/reducers.js +++ b/src/core/plugins/spec/reducers.js @@ -12,7 +12,7 @@ import { SET_REQUEST, SET_MUTATED_REQUEST, UPDATE_RESOLVED, - UPDATE_OPERATION_VALUE, + UPDATE_OPERATION_META_VALUE, CLEAR_RESPONSE, CLEAR_REQUEST, CLEAR_VALIDATE_PARAMS, @@ -52,8 +52,8 @@ export default { }, [VALIDATE_PARAMS]: ( state, { payload: { pathMethod, isOAS3 } } ) => { - let operation = state.getIn( [ "resolved", "paths", ...pathMethod ] ) - let isXml = /xml/i.test(operation.get("consumes_value")) + let meta = state.getIn( [ "meta", "paths", ...pathMethod ] ) + let isXml = /xml/i.test(meta.get("consumes_value")) return state.updateIn( [ "resolved", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => { return parameters.withMutations( parameters => { @@ -107,12 +107,17 @@ export default { return state.setIn( [ "mutatedRequests", path, method ], fromJSOrdered(req)) }, - [UPDATE_OPERATION_VALUE]: (state, { payload: { path, value, key } }) => { + [UPDATE_OPERATION_META_VALUE]: (state, { payload: { path, value, key } }) => { + // path is a pathMethod tuple... can't change the name now. let operationPath = ["resolved", "paths", ...path] + let metaPath = ["meta", "paths", ...path] + if(!state.getIn(operationPath)) { + // do nothing if the operation does not exist return state } - return state.setIn([...operationPath, key], fromJS(value)) + + return state.setIn([...metaPath, key], fromJS(value)) }, [CLEAR_RESPONSE]: (state, { payload: { path, method } } ) =>{ diff --git a/src/core/plugins/spec/selectors.js b/src/core/plugins/spec/selectors.js index aee730c9fff..e19c590c31b 100644 --- a/src/core/plugins/spec/selectors.js +++ b/src/core/plugins/spec/selectors.js @@ -306,10 +306,13 @@ export function parametersIncludeType(parameters, typeValue="") { export function contentTypeValues(state, pathMethod) { pathMethod = pathMethod || [] let op = spec(state).getIn(["paths", ...pathMethod], fromJS({})) + let meta = state.getIn(["meta", "paths", ...pathMethod], fromJS({})) + let producesValue = currentProducesFor(state, pathMethod) + const parameters = op.get("parameters") || new List() const requestContentType = ( - op.get("consumes_value") ? op.get("consumes_value") + meta.get("consumes_value") ? meta.get("consumes_value") : parametersIncludeType(parameters, "file") ? "multipart/form-data" : parametersIncludeType(parameters, "formData") ? "application/x-www-form-urlencoded" : undefined @@ -317,7 +320,7 @@ export function contentTypeValues(state, pathMethod) { return fromJS({ requestContentType, - responseContentType: op.get("produces_value") + responseContentType: producesValue }) } @@ -327,6 +330,24 @@ export function operationConsumes(state, pathMethod) { return spec(state).getIn(["paths", ...pathMethod, "consumes"], fromJS({})) } +// Get the currently selected produces value for an operation +export function currentProducesFor(state, pathMethod) { + pathMethod = pathMethod || [] + + const operation = spec(state).getIn(["paths", ...pathMethod], null) + + if(operation === null) { + // return nothing if the operation does not exist + return + } + + const currentProducesValue = state.getIn(["meta", "paths", ...pathMethod, "produces_value"], null) + const firstProducesArrayItem = operation.getIn(["produces", 0], null) + + return currentProducesValue || firstProducesArrayItem || "application/json" + +} + export const operationScheme = ( state, path, method ) => { let url = state.get("url") let matchResult = url.match(/^([a-z][a-z0-9+\-.]*):/) diff --git a/test/core/plugins/spec-reducer.js b/test/core/plugins/spec/reducer.js similarity index 89% rename from test/core/plugins/spec-reducer.js rename to test/core/plugins/spec/reducer.js index 09e73b7c900..1c91e054add 100644 --- a/test/core/plugins/spec-reducer.js +++ b/test/core/plugins/spec/reducer.js @@ -5,9 +5,9 @@ import reducer from "corePlugins/spec/reducers" describe("spec plugin - reducer", function(){ - describe("update operation value", function() { - it("should update the operation at the specified key", () => { - const updateOperationValue = reducer["spec_update_operation_value"] + describe("update operation meta value", function() { + it("should update the operation metadata at the specified key", () => { + const updateOperationValue = reducer["spec_update_operation_meta_value"] const state = fromJS({ resolved: { @@ -34,7 +34,15 @@ describe("spec plugin - reducer", function(){ "paths": { "/pet": { "post": { - "description": "my operation", + "description": "my operation" + } + } + } + }, + meta: { + paths: { + "/pet": { + post: { "consumes_value": "application/json" } } @@ -46,7 +54,7 @@ describe("spec plugin - reducer", function(){ }) it("shouldn't throw an error if we try to update the consumes_value of a null operation", () => { - const updateOperationValue = reducer["spec_update_operation_value"] + const updateOperationValue = reducer["spec_update_operation_meta_value"] const state = fromJS({ resolved: { diff --git a/test/core/plugins/spec/selectors.js b/test/core/plugins/spec/selectors.js index df6b1c219b0..824464899f9 100644 --- a/test/core/plugins/spec/selectors.js +++ b/test/core/plugins/spec/selectors.js @@ -56,6 +56,13 @@ describe("spec plugin - selectors", function(){ // Given let state = fromJS({ resolved: { + paths: { + "/one": { + get: {} + } + } + }, + meta: { paths: { "/one": { get: { @@ -76,6 +83,71 @@ describe("spec plugin - selectors", function(){ }) }) + it("should default to the first `produces` array value if current is not set", function(){ + // Given + let state = fromJS({ + resolved: { + paths: { + "/one": { + get: { + produces: [ + "application/xml", + "application/whatever" + ] + } + } + } + }, + meta: { + paths: { + "/one": { + get: { + "consumes_value": "one" + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS()).toEqual({ + requestContentType: "one", + responseContentType: "application/xml" + }) + }) + + it("should default to `application/json` if a default produces value is not available", function(){ + // Given + let state = fromJS({ + resolved: { + paths: { + "/one": { + get: {} + } + } + }, + meta: { + paths: { + "/one": { + get: { + "consumes_value": "one" + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS()).toEqual({ + requestContentType: "one", + responseContentType: "application/json" + }) + }) + it("should prioritize consumes value first from an operation", function(){ // Given let state = fromJS({ @@ -83,13 +155,21 @@ describe("spec plugin - selectors", function(){ paths: { "/one": { get: { - "consumes_value": "one", - "parameters": [{ + "parameters": [{ "type": "file" }], } } } + }, + meta: { + paths: { + "/one": { + get: { + "consumes_value": "one", + } + } + } } }) @@ -106,7 +186,7 @@ describe("spec plugin - selectors", function(){ paths: { "/one": { get: { - "parameters": [{ + "parameters": [{ "type": "file" }], } @@ -128,7 +208,7 @@ describe("spec plugin - selectors", function(){ paths: { "/one": { get: { - "parameters": [{ + "parameters": [{ "type": "formData" }], } @@ -143,7 +223,7 @@ describe("spec plugin - selectors", function(){ expect(contentTypes.toJS().requestContentType).toEqual("application/x-www-form-urlencoded") }) - it("should be ok, if no operation found", function(){ + it("should return nothing, if the operation does not exist", function(){ // Given let state = fromJS({ })