Skip to content

Commit

Permalink
feat: OAS3 binary media type support (#4592)
Browse files Browse the repository at this point in the history
* fix(validator-badge): resolve definition URLs against browser location

* use param as meta parameter if not found

* convert request body from Immutable if necessary

* show file upload for `format: binary` and `format: base64` jsonschema strings

* add `dispatchInitialValue` prop to JsonSchemaForm

* add optional subkey parameter to onChange

* add binary media type support to request body
  • Loading branch information
shockey authored May 26, 2018
1 parent cdbd120 commit 43304aa
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/core/components/param-body.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default class ParamBody extends PureComponent {

updateValues = (props) => {
let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props
let parameter = specSelectors ? specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in")) : fromJS({})
let parameter = (specSelectors ? specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in")) : fromJS({})) || param
let isXml = /xml/i.test(consumesValue)
let isJson = /json/i.test(consumesValue)
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
Expand Down
4 changes: 2 additions & 2 deletions src/core/components/parameter-row.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default class ParameterRow extends Component {
let { isOAS3 } = specSelectors

let example = param.get("example")
let parameter = specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in"))
let parameter = specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in")) || param
let enumValue

if(isOAS3()) {
Expand Down Expand Up @@ -156,7 +156,7 @@ export default class ParameterRow extends Component {
}

return (
<tr>
<tr className="parameters">
<td className="col parameters-col_name">
<div className={required ? "parameter__name required" : "parameter__name"}>
{ param.get("name") }
Expand Down
7 changes: 7 additions & 0 deletions src/core/json-schema-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ export class JsonSchemaForm extends Component {
static propTypes = JsonSchemaPropShape
static defaultProps = JsonSchemaDefaultProps

componentDidMount() {
const { dispatchInitialValue, value, onChange } = this.props
if(dispatchInitialValue) {
onChange(value)
}
}

render() {
let { schema, errors, value, onChange, getComponent, fn } = this.props

Expand Down
79 changes: 78 additions & 1 deletion src/core/plugins/oas3/components/request-body.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import { OrderedMap } from "immutable"
import { getSampleSchema } from "core/utils"
import Im, { Map, OrderedMap, List } from "immutable"

const RequestBody = ({
requestBody,
requestBodyValue,
getComponent,
getConfigs,
specSelectors,
Expand All @@ -13,6 +15,10 @@ const RequestBody = ({
specPath,
onChange
}) => {
const handleFile = (e) => {
onChange(e.target.files[0])
}

const Markdown = getComponent("Markdown")
const ModelExample = getComponent("modelExample")
const RequestBodyEditor = getComponent("RequestBodyEditor")
Expand All @@ -23,10 +29,80 @@ const RequestBody = ({

const mediaTypeValue = requestBodyContent.get(contentType)

const isObjectContent = mediaTypeValue.getIn(["schema", "type"]) === "object"

if(!mediaTypeValue) {
return null
}

if(contentType === "application/octet-stream") {
const Input = getComponent("Input")

if(!isExecute) {
return <i>
Example values are not available for <code>application/octet-stream</code> media types.
</i>
}

return <Input type={"file"} onChange={handleFile} />
}

if(
isObjectContent &&
(contentType === "application/x-www-form-urlencoded"
|| contentType.indexOf("multipart/") === 0))
{
const JsonSchemaForm = getComponent("JsonSchemaForm")
const HighlightCode = getComponent("highlightCode")
const bodyProperties = requestBody.getIn(["content", contentType, "schema", "properties"], OrderedMap())
requestBodyValue = Map.isMap(requestBodyValue) ? requestBodyValue : OrderedMap()

return <div className="table-container">
<table>
<tbody>
{
bodyProperties.map((prop, key) => {
const required = prop.get("required")
const type = prop.get("type")
const format = prop.get("format")

const isFile = type === "string" && (format === "binary" || format === "base64")

return <tr key={key} className="parameters">
<td className="col parameters-col_name">
<div className={required ? "parameter__name required" : "parameter__name"}>
{ key }
{ !required ? null : <span style={{color: "red"}}>&nbsp;*</span> }
</div>
<div className="parameter__type">
{ type }
{ format && <span className="prop-format">(${format})</span>}
</div>
<div className="parameter__deprecated">
{ prop.get("deprecated") ? "deprecated": null }
</div>
</td>
<td className="col parameters-col_description">
{isExecute ?
<JsonSchemaForm
dispatchInitialValue={!isFile}
schema={prop}
getComponent={getComponent}
value={requestBodyValue.get(key) || getSampleSchema(prop)}
onChange={(value) => {
onChange(value, [key])
}}
/>
: <HighlightCode className="example" value={ getSampleSchema(prop) } />}
</td>
</tr>
})
}
</tbody>
</table>
</div>
}

return <div>
{ requestBodyDescription &&
<Markdown source={requestBodyDescription} />
Expand All @@ -53,6 +129,7 @@ const RequestBody = ({

RequestBody.propTypes = {
requestBody: ImPropTypes.orderedMap.isRequired,
requestBodyValue: ImPropTypes.orderedMap.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
Expand Down
2 changes: 2 additions & 0 deletions src/core/plugins/oas3/wrap-components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import parameters from "./parameters"
import VersionStamp from "./version-stamp"
import OnlineValidatorBadge from "./online-validator-badge"
import Model from "./model"
import JsonSchema_string from "./json-schema-string"

export default {
Markdown,
AuthItem,
parameters,
JsonSchema_string,
VersionStamp,
model: Model,
onlineValidatorBadge: OnlineValidatorBadge,
Expand Down
26 changes: 26 additions & 0 deletions src/core/plugins/oas3/wrap-components/json-schema-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react"
import { OAS3ComponentWrapFactory } from "../helpers"

export default OAS3ComponentWrapFactory(({ Ori, ...props }) => {
const {
schema,
getComponent,
errors,
onChange
} = props

const { type, format } = schema
const Input = getComponent("Input")

if(type === "string" && (format === "binary" || format === "base64")) {
return <Input type="file"
className={ errors.length ? "invalid" : ""}
title={ errors.length ? errors : ""}
onChange={(e) => {
onChange(e.target.files[0])
}}
disabled={Ori.isDisabled}/>
} else {
return <Ori {...props} />
}
})
11 changes: 10 additions & 1 deletion src/core/plugins/oas3/wrap-components/parameters.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,17 @@ class Parameters extends Component {
<RequestBody
specPath={requestBodySpecPath}
requestBody={requestBody}
requestBodyValue={oas3Selectors.requestBodyValue(...pathMethod) || Map()}
isExecute={isExecute}
onChange={(value) => {
onChange={(value, path) => {
if(path) {
const lastValue = oas3Selectors.requestBodyValue(...pathMethod)
const usableValue = Map.isMap(lastValue) ? lastValue : Map()
return oas3Actions.setRequestBodyValue({
pathMethod,
value: usableValue.setIn(path, value)
})
}
oas3Actions.setRequestBodyValue({ value, pathMethod })
}}
contentType={oas3Selectors.requestContentType(...pathMethod)}/>
Expand Down
4 changes: 3 additions & 1 deletion src/core/plugins/spec/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,9 @@ export const executeRequest = (req) =>

if(isJSONObject(requestBody)) {
req.requestBody = JSON.parse(requestBody)
} else {
} else if(requestBody && requestBody.toJS) {
req.requestBody = requestBody.toJS()
} else{
req.requestBody = requestBody
}
}
Expand Down

0 comments on commit 43304aa

Please sign in to comment.