feat: support x-response-samples to render code responses

This commit is contained in:
Emmanuel Quentin 2018-10-03 21:09:39 +02:00
parent 3c8d6b623c
commit 5ea3dc68dd
7 changed files with 94 additions and 9 deletions

View File

@ -194,6 +194,7 @@ ReDoc makes use of the following [vendor extensions](http://swagger.io/specifica
* [`x-logo`](docs/redoc-vendor-extensions.md#x-logo) - is used to specify API logo * [`x-logo`](docs/redoc-vendor-extensions.md#x-logo) - is used to specify API logo
* [`x-traitTag`](docs/redoc-vendor-extensions.md#x-traitTag) - useful for handling out common things like Pagination, Rate-Limits, etc * [`x-traitTag`](docs/redoc-vendor-extensions.md#x-traitTag) - useful for handling out common things like Pagination, Rate-Limits, etc
* [`x-code-samples`](docs/redoc-vendor-extensions.md#x-code-samples) - specify operation code samples * [`x-code-samples`](docs/redoc-vendor-extensions.md#x-code-samples) - specify operation code samples
* [`x-response-samples`](docs/redoc-vendor-extensions.md#x-response-samples) - specify operation response code samples
* [`x-examples`](docs/redoc-vendor-extensions.md#x-examples) - specify JSON example for requests * [`x-examples`](docs/redoc-vendor-extensions.md#x-examples) - specify JSON example for requests
* [`x-nullable`](docs/redoc-vendor-extensions.md#nullable) - mark schema param as a nullable * [`x-nullable`](docs/redoc-vendor-extensions.md#nullable) - mark schema param as a nullable
* [`x-displayName`](docs/redoc-vendor-extensions.md#x-displayname) - specify human-friendly names for the menu categories * [`x-displayName`](docs/redoc-vendor-extensions.md#x-displayname) - specify human-friendly names for the menu categories

View File

@ -17,14 +17,14 @@ info:
It was **extended** to illustrate features of [generator-openapi-repo](https://github.com/Rebilly/generator-openapi-repo) It was **extended** to illustrate features of [generator-openapi-repo](https://github.com/Rebilly/generator-openapi-repo)
tool and [ReDoc](https://github.com/Rebilly/ReDoc) documentation. In addition to standard tool and [ReDoc](https://github.com/Rebilly/ReDoc) documentation. In addition to standard
OpenAPI syntax we use a few [vendor extensions](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md). OpenAPI syntax we use a few [vendor extensions](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md).
# OpenAPI Specification # OpenAPI Specification
This API is documented in **OpenAPI format** and is based on This API is documented in **OpenAPI format** and is based on
[Petstore sample](http://petstore.swagger.io/) provided by [swagger.io](http://swagger.io) team. [Petstore sample](http://petstore.swagger.io/) provided by [swagger.io](http://swagger.io) team.
It was **extended** to illustrate features of [generator-openapi-repo](https://github.com/Rebilly/generator-openapi-repo) It was **extended** to illustrate features of [generator-openapi-repo](https://github.com/Rebilly/generator-openapi-repo)
tool and [ReDoc](https://github.com/Rebilly/ReDoc) documentation. In addition to standard tool and [ReDoc](https://github.com/Rebilly/ReDoc) documentation. In addition to standard
OpenAPI syntax we use a few [vendor extensions](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md). OpenAPI syntax we use a few [vendor extensions](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md).
# Cross-Origin Resource Sharing # Cross-Origin Resource Sharing
This API features Cross-Origin Resource Sharing (CORS) implemented in compliance with [W3C spec](https://www.w3.org/TR/cors/). This API features Cross-Origin Resource Sharing (CORS) implemented in compliance with [W3C spec](https://www.w3.org/TR/cors/).
And that allows cross-domain communication from the browser. And that allows cross-domain communication from the browser.
@ -38,7 +38,7 @@ info:
OAuth2 - an open protocol to allow secure authorization in a simple OAuth2 - an open protocol to allow secure authorization in a simple
and standard method from web, mobile and desktop applications. and standard method from web, mobile and desktop applications.
<security-definitions /> <security-definitions />
version: 1.0.0 version: 1.0.0
title: Swagger Petstore title: Swagger Petstore
@ -187,6 +187,27 @@ paths:
description: Invalid ID supplied description: Invalid ID supplied
'404': '404':
description: Pet not found description: Pet not found
x-code-samples:
- lang: 'Javascript'
source: |
const pet = new PetStore.v1.Pet();
await pet.get(1, (err, pet);
x-response-samples:
- lang: 'Javascript'
source: |
Pet {
id: number;
name: String;
getName(): String;
}
- lang: 'Javascript'
label: 'Javascript error'
source: |
ServerResponse {
status: number;
message: String;
}
security: security:
- api_key: [] - api_key: []
post: post:

View File

@ -183,15 +183,54 @@ Operation code sample
###### Code Sample Object example ###### Code Sample Object example
json json
```json ```json
{ [
"lang": "JavaScript", {
"source": "console.log('Hello World');" "lang": "JavaScript",
} "source": "console.log('Hello World');"
}
]
``` ```
yaml yaml
```yaml ```yaml
lang: JavaScript -
source: console.log('Hello World'); lang: JavaScript
source: console.log('Hello World');
```
#### x-response-samples
| Field Name | Type | Description |
| :----------------- | :------: | :---------- |
| x-response-samples | [ [Code Sample Object](#responseSampleObject) ] | A list of response samples associated with operation, useful when your SDK renders different structure of your API |
###### Usage in ReDoc
`x-response-samples` are rendered on the right panel of ReDoc, after response tabs.
#### <a name="codeSampleObject"></a>Code Sample Object
Operation code sample
###### Fixed fields
| Field Name | Type | Description |
| :---------- | :------: | :----------- |
| lang | string | Code sample language. Value should be one of the following [list](https://github.com/github/linguist/blob/master/lib/linguist/popular.yml) |
| label | string? | Code sample label e.g. `Node` or `Python2.7`, _optional_, `lang` will be used by default |
| source | string | Code sample source code |
###### Response Sample Object example
json
```json
[
{
"lang": "JavaScript",
"source": "console.log('Hello World');"
}
]
```
yaml
```yaml
-
lang: JavaScript
source: console.log('Hello World');
``` ```
### Parameter Object vendor extensions ### Parameter Object vendor extensions

View File

@ -5,6 +5,7 @@ import { OperationModel } from '../../services/models';
import { RightPanelHeader, Tab, TabList, TabPanel, Tabs } from '../../common-elements'; import { RightPanelHeader, Tab, TabList, TabPanel, Tabs } from '../../common-elements';
import { PayloadSamples } from '../PayloadSamples/PayloadSamples'; import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
export interface ResponseSamplesProps { export interface ResponseSamplesProps {
operation: OperationModel; operation: OperationModel;
@ -16,6 +17,8 @@ export class ResponseSamples extends React.Component<ResponseSamplesProps> {
render() { render() {
const { operation } = this.props; const { operation } = this.props;
const samples = operation.responseSamples;
const responses = operation.responses.filter(response => { const responses = operation.responses.filter(response => {
return response.content && response.content.hasSample; return response.content && response.content.hasSample;
}); });
@ -32,6 +35,11 @@ export class ResponseSamples extends React.Component<ResponseSamplesProps> {
{response.code} {response.code}
</Tab> </Tab>
))} ))}
{samples.map(sample => (
<Tab key={`response-${sample.label || sample.lang}`}>
{sample.label || sample.lang}
</Tab>
))}
</TabList> </TabList>
{responses.map(response => ( {responses.map(response => (
<TabPanel key={response.code}> <TabPanel key={response.code}>
@ -40,6 +48,11 @@ export class ResponseSamples extends React.Component<ResponseSamplesProps> {
</div> </div>
</TabPanel> </TabPanel>
))} ))}
{samples.map(sample => (
<TabPanel key={`response-${sample.label || sample.lang}`}>
<SourceCodeWithCopy lang={sample.lang} source={sample.source} />
</TabPanel>
))}
</Tabs> </Tabs>
</div> </div>
)) || )) ||

View File

@ -9,6 +9,7 @@ import {
OpenAPIPath, OpenAPIPath,
OpenAPIServer, OpenAPIServer,
OpenAPIXCodeSample, OpenAPIXCodeSample,
OpenAPIXResponseSample,
} from '../../types'; } from '../../types';
import { import {
@ -62,6 +63,7 @@ export class OperationModel implements IMenuItem {
servers: OpenAPIServer[]; servers: OpenAPIServer[];
security: SecurityRequirementModel[]; security: SecurityRequirementModel[];
codeSamples: OpenAPIXCodeSample[]; codeSamples: OpenAPIXCodeSample[];
responseSamples: OpenAPIXResponseSample[];
extensions: Dict<any>; extensions: Dict<any>;
constructor( constructor(
@ -89,6 +91,7 @@ export class OperationModel implements IMenuItem {
this.deprecated = !!operationSpec.deprecated; this.deprecated = !!operationSpec.deprecated;
this.operationId = operationSpec.operationId; this.operationId = operationSpec.operationId;
this.codeSamples = operationSpec['x-code-samples'] || []; this.codeSamples = operationSpec['x-code-samples'] || [];
this.responseSamples = operationSpec['x-response-samples'] || [];
this.path = operationSpec.pathName; this.path = operationSpec.pathName;
const pathInfo = parser.byRef<OpenAPIPath>( const pathInfo = parser.byRef<OpenAPIPath>(

View File

@ -63,6 +63,12 @@ export interface OpenAPIXCodeSample {
source: string; source: string;
} }
export interface OpenAPIXResponseSample {
lang: string;
label?: string;
source: string;
}
export interface OpenAPIOperation { export interface OpenAPIOperation {
tags?: string[]; tags?: string[];
summary?: string; summary?: string;
@ -77,6 +83,7 @@ export interface OpenAPIOperation {
security?: OpenAPISecurityRequirement[]; security?: OpenAPISecurityRequirement[];
servers?: OpenAPIServer[]; servers?: OpenAPIServer[];
'x-code-samples'?: OpenAPIXCodeSample[]; 'x-code-samples'?: OpenAPIXCodeSample[];
'x-response-samples'?: OpenAPIXResponseSample[];
} }
export interface OpenAPIParameter { export interface OpenAPIParameter {

View File

@ -291,6 +291,7 @@ export function isRedocExtension(key: string): boolean {
const redocExtensions = { const redocExtensions = {
'x-circular-ref': true, 'x-circular-ref': true,
'x-code-samples': true, 'x-code-samples': true,
'x-response-samples': true,
'x-displayName': true, 'x-displayName': true,
'x-examples': true, 'x-examples': true,
'x-ignoredHeaderParameters': true, 'x-ignoredHeaderParameters': true,