Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: support for Parameter.content #5571

Merged
merged 20 commits into from
Aug 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
"remarkable": "^1.7.4",
"reselect": "^2.5.4",
"serialize-error": "^2.1.0",
"swagger-client": "^3.9.3",
"swagger-client": "^3.9.4",
"url-parse": "^1.4.7",
"xml-but-prettier": "^1.0.1",
"zenscroll": "^4.0.2"
Expand Down
67 changes: 53 additions & 14 deletions src/core/components/parameter-row.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { Map, List } from "immutable"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import win from "core/window"
import { getExtensions, getCommonExtensions, numberToString, stringify } from "core/utils"
import { getSampleSchema, getExtensions, getCommonExtensions, numberToString, stringify } from "core/utils"
import getParameterSchema from "../../helpers/get-parameter-schema.js"

export default class ParameterRow extends Component {
static propTypes = {
Expand Down Expand Up @@ -40,7 +41,7 @@ export default class ParameterRow extends Component {
let enumValue

if(isOAS3) {
let schema = parameterWithMeta.get("schema") || Map()
let schema = getParameterSchema(parameterWithMeta, { isOAS3 })
enumValue = schema.get("enum")
} else {
enumValue = parameterWithMeta ? parameterWithMeta.get("enum") : undefined
Expand Down Expand Up @@ -95,30 +96,68 @@ export default class ParameterRow extends Component {
setDefaultValue = () => {
let { specSelectors, pathMethod, rawParam, oas3Selectors } = this.props

let paramWithMeta = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam) || Map()
const paramWithMeta = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam) || Map()

const schema = getParameterSchema(paramWithMeta, { isOAS3: specSelectors.isOAS3() })

const parameterMediaType = paramWithMeta
.get("content", Map())
.keySeq()
.first()

const generatedSampleValue = getSampleSchema(schema.toJS(), parameterMediaType, {
includeWriteOnly: true
})

if (!paramWithMeta || paramWithMeta.get("value") !== undefined) {
return
}

if( paramWithMeta.get("in") !== "body" ) {
let newValue
let initialValue

//// Find an initial value

if (specSelectors.isSwagger2()) {
newValue = paramWithMeta.get("x-example")
|| paramWithMeta.getIn(["default"])
initialValue = paramWithMeta.get("x-example")
|| paramWithMeta.getIn(["schema", "example"])
|| paramWithMeta.getIn(["schema", "default"])
|| schema.getIn(["default"])
} else if (specSelectors.isOAS3()) {
const currentExampleKey = oas3Selectors.activeExamplesMember(...pathMethod, "parameters", this.getParamKey())
newValue = paramWithMeta.getIn(["examples", currentExampleKey, "value"])
initialValue = paramWithMeta.getIn(["examples", currentExampleKey, "value"])
|| paramWithMeta.getIn(["content", parameterMediaType, "example"])
|| paramWithMeta.get("example")
|| paramWithMeta.getIn(["schema", "example"])
|| paramWithMeta.getIn(["schema", "default"])
|| schema.get("example")
|| schema.get("default")
}
if(newValue !== undefined) {

//// Process the initial value

if(initialValue !== undefined && !List.isList(initialValue)) {
// Stringify if it isn't a List
initialValue = stringify(initialValue)
}

//// Dispatch the initial value

if(initialValue !== undefined) {
this.onChangeWrapper(initialValue)
} else if(
schema.get("type") === "object"
&& generatedSampleValue
&& !paramWithMeta.get("examples")
) {
// Object parameters get special treatment.. if the user doesn't set any
// default or example values, we'll provide initial values generated from
// the schema.
// However, if `examples` exist for the parameter, we won't do anything,
// so that the appropriate `examples` logic can take over.
this.onChangeWrapper(
List.isList(newValue) ? newValue : stringify(newValue)
List.isList(generatedSampleValue) ? (
generatedSampleValue
) : (
stringify(generatedSampleValue)
)
)
}
}
Expand Down Expand Up @@ -171,7 +210,7 @@ export default class ParameterRow extends Component {

let paramWithMeta = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam) || Map()
let format = param.get("format")
let schema = isOAS3 ? param.get("schema") : param
let schema = getParameterSchema(param, { isOAS3 })
let type = schema.get("type")
let isFormData = inType === "formData"
let isFormDataSupported = "FormData" in win
Expand Down Expand Up @@ -285,7 +324,7 @@ export default class ParameterRow extends Component {
getConfigs={ getConfigs }
isExecute={ isExecute }
specSelectors={ specSelectors }
schema={ param.get("schema") }
schema={ schema }
example={ bodyParam }/>
: null
}
Expand Down
3 changes: 2 additions & 1 deletion src/core/json-schema-components.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { List, fromJS } from "immutable"
import cx from "classnames"
import ImPropTypes from "react-immutable-proptypes"
import DebounceInput from "react-debounce-input"
import { stringify } from "core/utils"
//import "less/json-schema-form"

const noop = ()=> {}
Expand Down Expand Up @@ -269,7 +270,7 @@ export class JsonSchema_object extends PureComponent {
<TextArea
className={cx({ invalid: errors.size })}
title={ errors.size ? errors.join(", ") : ""}
value={value}
value={stringify(value)}
disabled={disabled}
onChange={ this.handleOnChange }/>
</div>
Expand Down
9 changes: 6 additions & 3 deletions src/core/plugins/spec/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,9 +436,12 @@ export const executeRequest = (req) =>
specActions.setResponse(req.pathName, req.method, res)
} )
.catch(
err => specActions.setResponse(req.pathName, req.method, {
error: true, err: serializeError(err)
})
err => {
console.error(err)
specActions.setResponse(req.pathName, req.method, {
error: true, err: serializeError(err)
})
}
)
}

Expand Down
38 changes: 28 additions & 10 deletions src/core/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
/*
ATTENTION! This file (but not the functions within) is deprecated.

You should probably add a new file to `./helpers/` instead of adding a new
function here.

One-function-per-file is a better pattern than what we have here.

If you're refactoring something in here, feel free to break it out to a file
in `./helpers` if you have the time.
*/

import Im from "immutable"
import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url"
import camelCase from "lodash/camelCase"
Expand All @@ -9,6 +21,7 @@ import eq from "lodash/eq"
import { memoizedSampleFromSchema, memoizedCreateXMLExample } from "core/plugins/samples/fn"
import win from "./window"
import cssEscape from "css.escape"
import getParameterSchema from "../helpers/get-parameter-schema"

const DEFAULT_RESPONSE_KEY = "default"

Expand Down Expand Up @@ -488,7 +501,7 @@ export const validateParam = (param, value, { isOAS3 = false, bypassRequiredChec
let errors = []
let required = param.get("required")

let paramDetails = isOAS3 ? param.get("schema") : param
let paramDetails = getParameterSchema(param, { isOAS3 })

if(!paramDetails) return errors

Expand Down Expand Up @@ -517,18 +530,23 @@ export const validateParam = (param, value, { isOAS3 = false, bypassRequiredChec

let oas3ObjectCheck = false

if(false || isOAS3 && type === "object") {
if(typeof value === "object") {
if(isOAS3 && type === "object") {
if(typeof value === "object" && value !== null) {
oas3ObjectCheck = true
} else if(typeof value === "string") {
try {
JSON.parse(value)
oas3ObjectCheck = true
} catch(e) {
errors.push("Parameter string value must be valid JSON")
return errors
}
oas3ObjectCheck = true
}
// Disabled because `validateParam` doesn't consider the MediaType of the
// `Parameter.content` hint correctly.
// } else if(typeof value === "string") {
// try {
// JSON.parse(value)
// oas3ObjectCheck = true
// } catch(e) {
// errors.push("Parameter string value must be valid JSON")
// return errors
// }
// }
}

const allChecks = [
Expand Down
67 changes: 67 additions & 0 deletions src/helpers/get-parameter-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* @prettier
*/

import Im from "immutable"

const swagger2SchemaKeys = Im.Set.of(
"type",
"format",
"items",
"default",
"maximum",
"exclusiveMaximum",
"minimum",
"exclusiveMinimum",
"maxLength",
"minLength",
"pattern",
"maxItems",
"minItems",
"uniqueItems",
"enum",
"multipleOf"
)

/**
* Get the effective schema value for a parameter, or an empty Immutable.Map if
* no suitable schema can be found.
*
* Supports OpenAPI 3.0 `Parameter.content` priority -- since a Parameter Object
* cannot have both `schema` and `content`, this function ignores `schema` when
* `content` is present.
*
* @param {Immutable.Map} parameter The parameter to identify a schema for
* @param {object} config
* @param {boolean} config.isOAS3 Whether the parameter is from an OpenAPI 2.0
* or OpenAPI 3.0 definition
* @return {Immutable.Map} The desired schema
*/
export default function getParameterSchema(parameter, { isOAS3 } = {}) {
// Return empty Map if `parameter` isn't a Map
if (!Im.Map.isMap(parameter)) return Im.Map()

if (!isOAS3) {
// Swagger 2.0
if (parameter.get("in") === "body") {
return parameter.get("schema", Im.Map())
} else {
return parameter.filter((v, k) => swagger2SchemaKeys.includes(k))
}
}

// If we've reached here, the parameter is OpenAPI 3.0

if (parameter.get("content")) {
const parameterContentMediaTypes = parameter
.get("content", Im.Map({}))
.keySeq()

return parameter.getIn(
["content", parameterContentMediaTypes.first(), "schema"],
Im.Map()
)
}

return parameter.get("schema", Im.Map())
}
Loading