diff --git a/src/core/components/headers.jsx b/src/core/components/headers.jsx
index c717b61e571..fa712fb5f04 100644
--- a/src/core/components/headers.jsx
+++ b/src/core/components/headers.jsx
@@ -1,6 +1,7 @@
import React from "react"
import PropTypes from "prop-types"
import Im from "immutable"
+import { getParameterExampleValue } from "core/utils/get-parameter-examples"
const propClass = "header-example"
@@ -19,7 +20,7 @@ export default class Headers extends React.Component {
if ( !headers || !headers.size )
return null
- return (
+ return (
Headers:
@@ -31,25 +32,25 @@ export default class Headers extends React.Component {
- {
- headers.entrySeq().map( ([ key, header ]) => {
- if(!Im.Map.isMap(header)) {
- return null
- }
-
- const description = header.get("description")
- const type = header.getIn(["schema"]) ? header.getIn(["schema", "type"]) : header.getIn(["type"])
- const schemaExample = header.getIn(["schema", "example"])
-
- return (
- | { key } |
- {
- !description ? null :
- } |
- { type } { schemaExample ? : null } |
-
)
- }).toArray()
- }
+ {
+ headers.entrySeq().map( ([ key, header ]) => {
+ if(!Im.Map.isMap(header)) {
+ return null
+ }
+
+ const description = header.get("description")
+ const type = header.getIn(["schema"]) ? header.getIn(["schema", "type"]) : header.getIn(["type"])
+ const headerExample = getParameterExampleValue(header)
+
+ return (
+ | { key } |
+ {
+ !description ? null :
+ } |
+ { type } { headerExample !== undefined ? : null } |
+
)
+ }).toArray()
+ }
diff --git a/src/core/components/parameter-row.jsx b/src/core/components/parameter-row.jsx
index 8b7ba16d165..3474dea2a97 100644
--- a/src/core/components/parameter-row.jsx
+++ b/src/core/components/parameter-row.jsx
@@ -4,6 +4,11 @@ import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import win from "core/window"
import { getExtensions, getCommonExtensions, numberToString, stringify, isEmptyValue } from "core/utils"
+import {
+ getParameterExample,
+ getParameterExampleValue,
+ getParameterExamples,
+} from "core/utils/get-parameter-examples"
import getParameterSchema from "core/utils/get-parameter-schema.js"
export default class ParameterRow extends Component {
@@ -102,6 +107,14 @@ export default class ParameterRow extends Component {
.get("content", Map())
.keySeq()
.first()
+ const currentExampleKey = oas3Selectors.activeExamplesMember(
+ ...pathMethod,
+ "parameters",
+ this.getParamKey()
+ )
+ const parameterExamples = getParameterExamples(paramWithMeta, {
+ parameterMediaType,
+ })
// getSampleSchema could return null
const generatedSampleValue = schema ? fn.getSampleSchema(schema.toJS(), parameterMediaType, {
@@ -121,26 +134,25 @@ export default class ParameterRow extends Component {
if (specSelectors.isSwagger2()) {
initialValue =
paramWithMeta.get("x-example") !== undefined
- ? paramWithMeta.get("x-example")
- : paramWithMeta.getIn(["schema", "example"]) !== undefined
- ? paramWithMeta.getIn(["schema", "example"])
- : (schema && schema.getIn(["default"]))
+ ? paramWithMeta.get("x-example")
+ : paramWithMeta.getIn(["schema", "example"]) !== undefined
+ ? paramWithMeta.getIn(["schema", "example"])
+ : (schema && schema.getIn(["default"]))
} else if (specSelectors.isOAS3()) {
schema = this.composeJsonSchema(schema)
- const currentExampleKey = oas3Selectors.activeExamplesMember(...pathMethod, "parameters", this.getParamKey())
initialValue =
- paramWithMeta.getIn(["examples", currentExampleKey, "value"]) !== undefined
- ? paramWithMeta.getIn(["examples", currentExampleKey, "value"])
- : paramWithMeta.getIn(["content", parameterMediaType, "example"]) !== undefined
- ? paramWithMeta.getIn(["content", parameterMediaType, "example"])
- : paramWithMeta.get("example") !== undefined
- ? paramWithMeta.get("example")
- : (schema && schema.get("example")) !== undefined
- ? (schema && schema.get("example"))
- : (schema && schema.get("default")) !== undefined
- ? (schema && schema.get("default"))
- : paramWithMeta.get("default") // ensures support for `parameterMacro`
+ getParameterExampleValue(paramWithMeta, {
+ parameterMediaType,
+ activeExampleKey: currentExampleKey,
+ }) !== undefined
+ ? getParameterExampleValue(paramWithMeta, {
+ parameterMediaType,
+ activeExampleKey: currentExampleKey,
+ })
+ : (schema && schema.get("default")) !== undefined
+ ? (schema && schema.get("default"))
+ : paramWithMeta.get("default") // ensures support for `parameterMacro`
}
//// Process the initial value
@@ -160,7 +172,7 @@ export default class ParameterRow extends Component {
} else if(
schemaObjectType === "object"
&& generatedSampleValue
- && !paramWithMeta.get("examples")
+ && !parameterExamples
) {
// Object parameters get special treatment.. if the user doesn't set any
// default or example values, we'll provide initial values generated from
@@ -179,7 +191,7 @@ export default class ParameterRow extends Component {
schemaObjectType === "array"
&& schemaItemsType === "object"
&& generatedSampleValue
- && !paramWithMeta.get("examples")
+ && !parameterExamples
) {
this.onChangeWrapper(
List.isList(generatedSampleValue) ? (
@@ -226,16 +238,16 @@ export default class ParameterRow extends Component {
let inType = param.get("in")
let bodyParam = inType !== "body" ? null
:
const ModelExample = getComponent("modelExample")
@@ -251,6 +263,12 @@ export default class ParameterRow extends Component {
.get("content", Map())
.keySeq()
.first()
+ const currentExampleKey = isOAS3
+ ? oas3Selectors.activeExamplesMember(...pathMethod, "parameters", this.getParamKey())
+ : undefined
+ const parameterExamples = isOAS3
+ ? getParameterExamples(param, { parameterMediaType })
+ : undefined
if (isOAS3) {
schema = this.composeJsonSchema(schema)
@@ -300,7 +318,12 @@ export default class ParameterRow extends Component {
if (paramDefaultValue === undefined) {
paramDefaultValue = param.get("default")
}
- paramExample = param.get("example")
+ paramExample = isOAS3
+ ? getParameterExampleValue(param, {
+ parameterMediaType,
+ activeExampleKey: currentExampleKey,
+ })
+ : param.get("example")
if (paramExample === undefined) {
paramExample = param.get("x-example")
}
@@ -340,9 +363,9 @@ export default class ParameterRow extends Component {
{ (bodyParam || !isExecute) && isDisplayParamEnum ?
Available values : " + paramEnum.map(function(item) {
- return item
- }).toArray().map(String).join(", ")}/>
+ "Available values : " + paramEnum.map(function(item) {
+ return item
+ }).toArray().map(String).join(", ")}/>
: null
}
@@ -359,15 +382,15 @@ export default class ParameterRow extends Component {
{(isFormData && !isFormDataSupported) && Error: your browser does not support FormData
}
{
- isOAS3 && param.get("examples") ? (
+ isOAS3 && parameterExamples ? (
@@ -388,37 +411,37 @@ export default class ParameterRow extends Component {
schema={schema}
example={jsonSchemaForm}
/>
- ) : jsonSchemaForm
+ ) : jsonSchemaForm
}
{
bodyParam && schema ?
+ specPath={specPath.push("schema")}
+ getConfigs={ getConfigs }
+ isExecute={ isExecute }
+ specSelectors={ specSelectors }
+ schema={ schema }
+ example={ bodyParam }
+ includeWriteOnly={ true }/>
: null
}
{
!bodyParam && isExecute && param.get("allowEmptyValue") ?
-
- : null
+
+ : null
}
{
- isOAS3 && param.get("examples") ? (
+ isOAS3 && parameterExamples ? (
diff --git a/src/core/utils/get-parameter-examples.js b/src/core/utils/get-parameter-examples.js
new file mode 100644
index 00000000000..fc49ab8ce08
--- /dev/null
+++ b/src/core/utils/get-parameter-examples.js
@@ -0,0 +1,117 @@
+/**
+ * @prettier
+ */
+
+import Im from "immutable"
+
+const getCurrentExample = (examples, activeExampleKey) => {
+ if (!Im.Map.isMap(examples) || !examples.size) {
+ return undefined
+ }
+
+ if (
+ activeExampleKey !== undefined &&
+ activeExampleKey !== null &&
+ examples.has(activeExampleKey)
+ ) {
+ return examples.get(activeExampleKey)
+ }
+
+ return examples.first()
+}
+
+const getExampleValue = (example) => {
+ if (Im.Map.isMap(example)) {
+ return example.get("value")
+ }
+
+ return example
+}
+
+const getParameterMediaType = (parameter, parameterMediaType) => {
+ if (parameterMediaType) {
+ return parameterMediaType
+ }
+
+ return parameter.get("content", Im.Map()).keySeq().first()
+}
+
+export const getParameterExamples = (
+ parameter,
+ { parameterMediaType } = {}
+) => {
+ if (!Im.Map.isMap(parameter)) {
+ return undefined
+ }
+
+ const examples = parameter.get("examples")
+
+ if (Im.Map.isMap(examples) && examples.size) {
+ return examples
+ }
+
+ const mediaType = getParameterMediaType(parameter, parameterMediaType)
+ const contentExamples = mediaType
+ ? parameter.getIn(["content", mediaType, "examples"])
+ : undefined
+
+ if (Im.Map.isMap(contentExamples) && contentExamples.size) {
+ return contentExamples
+ }
+
+ return undefined
+}
+
+export const getParameterExample = (
+ parameter,
+ { parameterMediaType, activeExampleKey } = {}
+) => {
+ const examples = getParameterExamples(parameter, { parameterMediaType })
+
+ if (!examples) {
+ return undefined
+ }
+
+ return getCurrentExample(examples, activeExampleKey)
+}
+
+export const getParameterExampleValue = (
+ parameter,
+ { parameterMediaType, activeExampleKey } = {}
+) => {
+ if (!Im.Map.isMap(parameter)) {
+ return undefined
+ }
+
+ const exampleValue = getExampleValue(
+ getParameterExample(parameter, { parameterMediaType, activeExampleKey })
+ )
+
+ if (exampleValue !== undefined) {
+ return exampleValue
+ }
+
+ const mediaType = getParameterMediaType(parameter, parameterMediaType)
+ const contentExample = mediaType
+ ? parameter.getIn(["content", mediaType, "example"])
+ : undefined
+
+ if (contentExample !== undefined) {
+ return contentExample
+ }
+
+ if (parameter.get("example") !== undefined) {
+ return parameter.get("example")
+ }
+
+ const schemaExamples = parameter.getIn(["schema", "examples"])
+ const firstSchemaExample = Im.Iterable.isIndexed(schemaExamples)
+ ? schemaExamples.first()
+ : undefined
+
+ if (firstSchemaExample !== undefined) {
+ return firstSchemaExample
+ }
+
+ return parameter.getIn(["schema", "example"])
+}
diff --git a/src/style/main.scss b/src/style/main.scss
index f5da6aceed8..0ed24f55f09 100644
--- a/src/style/main.scss
+++ b/src/style/main.scss
@@ -4,7 +4,7 @@
.swagger-ui {
container-name: swagger-ui;
container-type: inline-size;
-
+
@include type.text_body();
@include meta.load-css("~tachyons-sass/tachyons.scss");
@include meta.load-css("mixins");
diff --git a/test/unit/components/headers.jsx b/test/unit/components/headers.jsx
new file mode 100644
index 00000000000..3ca68fe5f12
--- /dev/null
+++ b/test/unit/components/headers.jsx
@@ -0,0 +1,92 @@
+import React from "react"
+import { fromJS } from "immutable"
+import { render } from "enzyme"
+
+import Headers from "core/components/headers"
+import Property from "core/components/property"
+
+describe("", function () {
+ const components = {
+ Property,
+ Markdown: ({ source }) => {source},
+ }
+
+ const getComponent = componentName => components[componentName]
+
+ it("renders the first OpenAPI 3 `examples` value for headers", function () {
+ const headers = fromJS({
+ "X-Rate-Limit": {
+ description: "Rate limit header",
+ schema: {
+ type: "integer",
+ example: 999,
+ },
+ example: 777,
+ examples: {
+ primary: {
+ summary: "Preferred",
+ value: 123,
+ },
+ secondary: {
+ value: 456,
+ },
+ },
+ },
+ })
+
+ const wrapper = render()
+ expect(wrapper.text()).toContain("Example: 123")
+ expect(wrapper.text()).not.toContain("Example: 777")
+ expect(wrapper.text()).not.toContain("Example: 999")
+ })
+
+ it("falls back to schema.examples when header.examples is absent", function () {
+ const headers = fromJS({
+ "X-Request-ID": {
+ description: "Request id",
+ schema: {
+ type: "string",
+ examples: ["abc123", "def456"],
+ },
+ },
+ })
+
+ const wrapper = render()
+ expect(wrapper.text()).toContain("Example: abc123")
+ })
+
+ it("falls back to content.examples when a header uses content", function () {
+ const headers = fromJS({
+ "X-Trace": {
+ description: "Trace header",
+ content: {
+ "text/plain": {
+ examples: {
+ primary: {
+ value: "trace-123",
+ },
+ },
+ },
+ },
+ },
+ })
+
+ const wrapper = render()
+ expect(wrapper.text()).toContain("Example: trace-123")
+ })
+
+ it("falls back to deprecated singular example and supports falsy values", function () {
+ const headers = fromJS({
+ "X-Deprecated": {
+ description: "Deprecated example usage",
+ schema: {
+ type: "integer",
+ },
+ example: 0,
+ },
+ })
+
+ const wrapper = render()
+ expect(wrapper.text()).toContain("Example: 0")
+ })
+})
diff --git a/test/unit/components/parameter-row.jsx b/test/unit/components/parameter-row.jsx
index 862a055c4de..86ab6f9d275 100644
--- a/test/unit/components/parameter-row.jsx
+++ b/test/unit/components/parameter-row.jsx
@@ -363,4 +363,128 @@ describe("bug #5573: zero default and example values", function () {
expect(props.onChange).toHaveBeenCalled()
expect(props.onChange).toHaveBeenCalledWith(paramValue, "0", false)
})
+
+ it("should apply the first OpenAPI 3.1 schema.examples value", function () {
+ const paramValue = fromJS({
+ name: "traceId",
+ in: "header",
+ schema: {
+ type: "string",
+ examples: ["abc123", "def456"],
+ },
+ })
+ const getSystem = () => ({
+ getComponent: () => "div",
+ specSelectors: {
+ security() {},
+ parameterWithMetaByIdentity() {
+ return paramValue
+ },
+ isOAS3() {
+ return true
+ },
+ isSwagger2() {
+ return false
+ },
+ },
+ oas3Selectors: {
+ activeExamplesMember: () => null,
+ },
+ getConfigs: () => {
+ return {}
+ },
+ fn: {
+ memoizedSampleFromSchema,
+ memoizedCreateXMLExample,
+ getSchemaObjectTypeLabel,
+ getSchemaObjectType,
+ getJsonSampleSchema: makeGetJsonSampleSchema(getSystem),
+ getYamlSampleSchema: makeGetYamlSampleSchema(getSystem),
+ getXmlSampleSchema: makeGetXmlSampleSchema(getSystem),
+ getSampleSchema: makeGetSampleSchema(getSystem),
+ mergeJsonSchema,
+ },
+ })
+ const props = {
+ ...getSystem(),
+ operation: { get: () => {} },
+ onChange: jest.fn(),
+ param: paramValue,
+ rawParam: paramValue,
+ onChangeConsumes: () => {},
+ pathMethod: [],
+ specPath: List([]),
+ }
+
+ render()
+
+ expect(props.onChange).toHaveBeenCalled()
+ expect(props.onChange).toHaveBeenCalledWith(paramValue, "abc123", false)
+ })
+
+ it("should apply the first OpenAPI 3 content.examples value", function () {
+ const paramValue = fromJS({
+ name: "traceId",
+ in: "header",
+ content: {
+ "text/plain": {
+ schema: {
+ type: "string",
+ },
+ examples: {
+ primary: {
+ value: "trace-123",
+ },
+ },
+ },
+ },
+ })
+ const getSystem = () => ({
+ getComponent: () => "div",
+ specSelectors: {
+ security() {},
+ parameterWithMetaByIdentity() {
+ return paramValue
+ },
+ isOAS3() {
+ return true
+ },
+ isSwagger2() {
+ return false
+ },
+ },
+ oas3Selectors: {
+ activeExamplesMember: () => null,
+ },
+ getConfigs: () => {
+ return {}
+ },
+ fn: {
+ memoizedSampleFromSchema,
+ memoizedCreateXMLExample,
+ getSchemaObjectTypeLabel,
+ getSchemaObjectType,
+ getJsonSampleSchema: makeGetJsonSampleSchema(getSystem),
+ getYamlSampleSchema: makeGetYamlSampleSchema(getSystem),
+ getXmlSampleSchema: makeGetXmlSampleSchema(getSystem),
+ getSampleSchema: makeGetSampleSchema(getSystem),
+ mergeJsonSchema,
+ },
+ })
+ const props = {
+ ...getSystem(),
+ operation: { get: () => {} },
+ onChange: jest.fn(),
+ param: paramValue,
+ rawParam: paramValue,
+ onChangeConsumes: () => {},
+ pathMethod: [],
+ specPath: List([]),
+ }
+
+ render()
+
+ expect(props.onChange).toHaveBeenCalled()
+ expect(props.onChange).toHaveBeenCalledWith(paramValue, "trace-123", false)
+ })
})