Skip to content

Commit 6a4e52a

Browse files
authored
feat: support for showExtensions on Response objects (#6535)
1 parent 50e5f65 commit 6a4e52a

File tree

9 files changed

+115
-2
lines changed

9 files changed

+115
-2
lines changed

docs/usage/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ Parameter name | Docker variable | Description
5656
<a name="filter"></a>`filter` | `FILTER` | `Boolean=false OR String`. If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. Can be Boolean to enable or disable, or a string, in which case filtering will be enabled using that string as the filter expression. Filtering is case sensitive matching the filter expression anywhere inside the tag.
5757
<a name="maxDisplayedTags"></a>`maxDisplayedTags` | `MAX_DISPLAYED_TAGS` | `Number`. If set, limits the number of tagged operations displayed to at most this many. The default is to show all operations.
5858
<a name="operationsSorter"></a>`operationsSorter` | _Unavailable_ | `Function=(a => a)`. Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
59-
<a name="showExtensions"></a>`showExtensions` | `SHOW_EXTENSIONS` | `Boolean=false`. Controls the display of vendor extension (`x-`) fields and values for Operations, Parameters, and Schema.
59+
<a name="showExtensions"></a>`showExtensions` | `SHOW_EXTENSIONS` | `Boolean=false`. Controls the display of vendor extension (`x-`) fields and values for Operations, Parameters, Responses, and Schema.
6060
<a name="showCommonExtensions"></a>`showCommonExtensions` | `SHOW_COMMON_EXTENSIONS` | `Boolean=false`. Controls the display of extensions (`pattern`, `maxLength`, `minLength`, `maximum`, `minimum`) fields and values for Parameters.
6161
<a name="tagSorter"></a>`tagsSorter` | _Unavailable_ | `Function=(a => a)`. Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger UI.
6262
<a name="useUnsafeMarkdown"></a>`useUnsafeMarkdown` | `USE_UNSAFE_MARKDOWN` | `Boolean=false`. When enabled, sanitizer will leave `style`, `class` and `data-*` attributes untouched on all HTML Elements declared inside markdown strings. This parameter is **Deprecated** and will be removed in `4.0.0`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from "react"
2+
import PropTypes from "prop-types"
3+
4+
export const ResponseExtension = ({ xKey, xVal }) => {
5+
return <div className="response__extension">{ xKey }: { String(xVal) }</div>
6+
}
7+
ResponseExtension.propTypes = {
8+
xKey: PropTypes.string,
9+
xVal: PropTypes.any
10+
}
11+
12+
export default ResponseExtension

src/core/components/response.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import PropTypes from "prop-types"
33
import ImPropTypes from "react-immutable-proptypes"
44
import cx from "classnames"
55
import { fromJS, Seq, Iterable, List, Map } from "immutable"
6-
import { getSampleSchema, fromJSOrdered, stringify } from "core/utils"
6+
import { getExtensions, getSampleSchema, fromJSOrdered, stringify } from "core/utils"
77
import { isFunc } from "../utils"
88

99
const getExampleComponent = ( sampleResponse, HighlightCode, getConfigs ) => {
@@ -88,9 +88,12 @@ export default class Response extends React.Component {
8888

8989
let { inferSchema } = fn
9090
let isOAS3 = specSelectors.isOAS3()
91+
const { showExtensions } = getConfigs()
9192

93+
let extensions = showExtensions ? getExtensions(response) : null
9294
let headers = response.get("headers")
9395
let links = response.get("links")
96+
const ResponseExtension = getComponent("ResponseExtension")
9497
const Headers = getComponent("headers")
9598
const HighlightCode = getComponent("highlightCode")
9699
const ModelExample = getComponent("modelExample")
@@ -188,6 +191,8 @@ export default class Response extends React.Component {
188191
<Markdown source={ response.get( "description" ) } />
189192
</div>
190193

194+
{ !showExtensions || !extensions.size ? null : extensions.map((v, key) => <ResponseExtension key={`${key}-${v}`} xKey={key} xVal={v} /> )}
195+
191196
{isOAS3 && response.get("content") ? (
192197
<section className="response-controls">
193198
<div

src/core/presets/base.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import OperationExtRow from "core/components/operation-extension-row"
4343
import HighlightCode from "core/components/highlight-code"
4444
import Responses from "core/components/responses"
4545
import Response from "core/components/response"
46+
import ResponseExtension from "core/components/response-extension"
4647
import ResponseBody from "core/components/response-body"
4748
import { Parameters } from "core/components/parameters"
4849
import ParameterExt from "core/components/parameter-extension"
@@ -119,6 +120,7 @@ export default function() {
119120
highlightCode: HighlightCode,
120121
responses: Responses,
121122
response: Response,
123+
ResponseExtension: ResponseExtension,
122124
responseBody: ResponseBody,
123125
parameters: Parameters,
124126
parameterRow: ParameterRow,

src/style/_table.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,11 @@ table
184184
.response-col_links {
185185
min-width: 6em;
186186
}
187+
188+
.response__extension
189+
{
190+
font-size: 12px;
191+
font-style: italic;
192+
193+
@include text_code($table-parameter-in-font-color);
194+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
openapi: "3.0.0"
2+
3+
paths:
4+
/:
5+
get:
6+
operationId: "myOperation"
7+
tags: ["myTag"]
8+
summary: an operation
9+
responses:
10+
'200':
11+
description: a pet to be returned
12+
content:
13+
application/json:
14+
schema:
15+
type: object
16+
'404':
17+
x-error: true
18+
x-error-codes: [NOT_FOUND]
19+
description: Not found
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
swagger: "2.0"
2+
3+
paths:
4+
/:
5+
get:
6+
operationId: "myOperation"
7+
tags: ["myTag"]
8+
summary: an operation
9+
responses:
10+
"200":
11+
description: ok
12+
'404':
13+
x-error: true
14+
x-error-codes: [NOT_FOUND]
15+
description: Not found
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
describe("Response extension feature", () => {
2+
describe("in Swagger 2", () => {
3+
const swagger2BaseUrl = "/?showExtensions=true&docExpansion=full&url=/documents/features/response-extension.swagger.yaml"
4+
5+
describe("without x- values", () => {
6+
it("should omit response extensions section", () => {
7+
cy.visit(swagger2BaseUrl)
8+
.get("tr.response[data-code='200'] td.response-col_description div.response__extension")
9+
.should("not.exist")
10+
})
11+
})
12+
13+
describe("with x- values", () => {
14+
it("should list each value", () => {
15+
const page = cy.visit(swagger2BaseUrl)
16+
17+
page.get("tr.response[data-code='404'] td.response-col_description div.response__extension:nth-child(2)")
18+
.should("have.text", "x-error: true")
19+
20+
page.get("tr.response[data-code='404'] td.response-col_description div.response__extension:nth-child(3)")
21+
.should("have.text", "x-error-codes: List [ \"NOT_FOUND\" ]")
22+
})
23+
})
24+
})
25+
26+
describe("in OpenAPI 3", () => {
27+
const openAPI3BaseUrl = "/?showExtensions=true&docExpansion=full&url=/documents/features/response-extension.openapi.yaml"
28+
29+
describe("without x- values", () => {
30+
it("should omit response extensions section", () => {
31+
cy.visit(openAPI3BaseUrl)
32+
.get("tr.response[data-code='200'] td.response-col_description div.response__extension")
33+
.should("not.exist")
34+
})
35+
})
36+
37+
describe("with x- values", () => {
38+
it("should list each value", () => {
39+
const page = cy.visit(openAPI3BaseUrl)
40+
41+
page.get("tr.response[data-code='404'] td.response-col_description div.response__extension:nth-child(2)")
42+
.should("have.text", "x-error: true")
43+
44+
page.get("tr.response[data-code='404'] td.response-col_description div.response__extension:nth-child(3)")
45+
.should("have.text", "x-error-codes: List [ \"NOT_FOUND\" ]")
46+
})
47+
})
48+
})
49+
})

test/unit/components/response.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ describe("<Response />", function () {
1717
}
1818
const props = {
1919
getComponent: c => components[c],
20+
getConfigs: () => {
21+
return {}
22+
},
2023
specSelectors: {
2124
isOAS3() {
2225
return false

0 commit comments

Comments
 (0)