mirror of
https://github.com/Redocly/redoc.git
synced 2025-08-09 22:54:51 +03:00
feat: ConsoleViewer can send the proper request customized by user now
This commit is contained in:
parent
e80fe1d47c
commit
2a927eb27c
|
@ -1,8 +1,8 @@
|
||||||
openapi: 3.0.0
|
openapi: 3.0.0
|
||||||
servers:
|
servers:
|
||||||
- url: //petstore.swagger.io/v2
|
- url: https://petstore.swagger.io/v2
|
||||||
description: Default server
|
description: Default server
|
||||||
- url: //petstore.swagger.io/sandbox
|
- url: https://petstore.swagger.io/sandbox
|
||||||
description: Sandbox server
|
description: Sandbox server
|
||||||
info:
|
info:
|
||||||
description: |
|
description: |
|
||||||
|
@ -101,7 +101,7 @@ paths:
|
||||||
'405':
|
'405':
|
||||||
description: Invalid input
|
description: Invalid input
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
x-code-samples:
|
x-code-samples:
|
||||||
|
@ -149,7 +149,7 @@ paths:
|
||||||
'405':
|
'405':
|
||||||
description: Validation exception
|
description: Validation exception
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
x-code-samples:
|
x-code-samples:
|
||||||
|
@ -217,7 +217,7 @@ paths:
|
||||||
'405':
|
'405':
|
||||||
description: Invalid input
|
description: Invalid input
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
requestBody:
|
requestBody:
|
||||||
|
@ -256,7 +256,7 @@ paths:
|
||||||
'400':
|
'400':
|
||||||
description: Invalid pet value
|
description: Invalid pet value
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
'/pet/{petId}/uploadImage':
|
'/pet/{petId}/uploadImage':
|
||||||
|
@ -282,7 +282,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/ApiResponse'
|
$ref: '#/components/schemas/ApiResponse'
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
requestBody:
|
requestBody:
|
||||||
|
@ -332,7 +332,7 @@ paths:
|
||||||
'400':
|
'400':
|
||||||
description: Invalid status value
|
description: Invalid status value
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
/pet/findByTags:
|
/pet/findByTags:
|
||||||
|
@ -372,7 +372,7 @@ paths:
|
||||||
'400':
|
'400':
|
||||||
description: Invalid tag value
|
description: Invalid tag value
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
/store/inventory:
|
/store/inventory:
|
||||||
|
@ -923,7 +923,7 @@ components:
|
||||||
description: List of user object
|
description: List of user object
|
||||||
required: true
|
required: true
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
petstore_auth:
|
authorization:
|
||||||
description: |
|
description: |
|
||||||
Get access to data while protecting your account credentials.
|
Get access to data while protecting your account credentials.
|
||||||
OAuth2 is also a safer and more secure way to give you access.
|
OAuth2 is also a safer and more secure way to give you access.
|
||||||
|
|
|
@ -25,9 +25,7 @@ const specUrl =
|
||||||
(userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml');
|
(userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml');
|
||||||
|
|
||||||
let store;
|
let store;
|
||||||
const headers = {
|
const headers = {};
|
||||||
'x-nutanix-client': 'ui',
|
|
||||||
};
|
|
||||||
const options: RedocRawOptions = { nativeScrollbars: false, enableConsole: true, providedByName: 'Intent ApiDocs by Nutanix', providedByUri: 'http://www.nutanix.com', additionalHeaders: headers };
|
const options: RedocRawOptions = { nativeScrollbars: false, enableConsole: true, providedByName: 'Intent ApiDocs by Nutanix', providedByUri: 'http://www.nutanix.com', additionalHeaders: headers };
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { SecuritySchemeModel } from '../../../typings/services/models';
|
||||||
import { SubmitButton } from '../../common-elements/buttons';
|
import { SubmitButton } from '../../common-elements/buttons';
|
||||||
import { FlexLayoutReverse } from '../../common-elements/panels';
|
import { FlexLayoutReverse } from '../../common-elements/panels';
|
||||||
import { FieldModel, OperationModel } from '../../services/models';
|
import { FieldModel, OperationModel, SecuritySchemesModel } from '../../services/models';
|
||||||
import { OpenAPISchema } from '../../types';
|
|
||||||
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
|
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
|
||||||
import { ConsoleEditor } from './ConsoleEditor';
|
import { ConsoleEditor } from './ConsoleEditor';
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ export interface ConsoleViewerProps {
|
||||||
additionalHeaders?: object;
|
additionalHeaders?: object;
|
||||||
queryParamPrefix?: string;
|
queryParamPrefix?: string;
|
||||||
queryParamSuffix?: string;
|
queryParamSuffix?: string;
|
||||||
|
securitySchemes: SecuritySchemesModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConsoleViewerState {
|
export interface ConsoleViewerState {
|
||||||
|
@ -22,7 +23,6 @@ export interface ConsoleViewerState {
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
_$ref?: any;
|
_$ref?: any;
|
||||||
rawSchema?: OpenAPISchema;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
|
@ -40,7 +40,8 @@ export class ConsoleViewer extends React.Component<ConsoleViewerProps, ConsoleVi
|
||||||
}
|
}
|
||||||
onClickSend = async () => {
|
onClickSend = async () => {
|
||||||
const ace = this.consoleEditor && this.consoleEditor.editor;
|
const ace = this.consoleEditor && this.consoleEditor.editor;
|
||||||
const { operation, additionalHeaders = {} } = this.props;
|
const { operation, securitySchemes: {schemes}, additionalHeaders = {} } = this.props;
|
||||||
|
|
||||||
let value = ace && ace.editor.getValue();
|
let value = ace && ace.editor.getValue();
|
||||||
|
|
||||||
const content = operation.requestBody && operation.requestBody.content;
|
const content = operation.requestBody && operation.requestBody.content;
|
||||||
|
@ -54,7 +55,23 @@ export class ConsoleViewer extends React.Component<ConsoleViewerProps, ConsoleVi
|
||||||
}
|
}
|
||||||
const contentType = mediaType && mediaType.name || 'application/json';
|
const contentType = mediaType && mediaType.name || 'application/json';
|
||||||
const contentTypeHeader = { 'Content-Type': contentType };
|
const contentTypeHeader = { 'Content-Type': contentType };
|
||||||
const headers = { ...additionalHeaders, ...contentTypeHeader };
|
|
||||||
|
const schemeMapper: Map<string, SecuritySchemeModel> = new Map<string, SecuritySchemeModel>();
|
||||||
|
schemes.forEach(scheme => {
|
||||||
|
schemeMapper.set(scheme.id, scheme);
|
||||||
|
});
|
||||||
|
|
||||||
|
const securityHeaders: Dict<string | undefined> = {};
|
||||||
|
|
||||||
|
operation.security.forEach(({schemes: [{ id }]}) => {
|
||||||
|
if (schemeMapper.has(id)) {
|
||||||
|
// this part of code needs a ts-ignore because typescript couldn't detect that schemeMapper.get(id) -
|
||||||
|
// has been checked to avoid token of undefined.
|
||||||
|
// @ts-ignore
|
||||||
|
securityHeaders[id] = schemeMapper.get(id).token;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const headers = { ...additionalHeaders, ...contentTypeHeader, ...securityHeaders };
|
||||||
let result;
|
let result;
|
||||||
try {
|
try {
|
||||||
result = await this.invoke(endpoint, value, headers);
|
result = await this.invoke(endpoint, value, headers);
|
||||||
|
@ -76,8 +93,6 @@ export class ConsoleViewer extends React.Component<ConsoleViewerProps, ConsoleVi
|
||||||
const queryParamSuffix = '}';
|
const queryParamSuffix = '}';
|
||||||
|
|
||||||
for (const fieldModel of params) {
|
for (const fieldModel of params) {
|
||||||
console.log(fieldModel.name + ' ' + url);
|
|
||||||
console.log(fieldModel.$value);
|
|
||||||
if (url.indexOf(`${queryParamPrefix}${fieldModel.name}${queryParamSuffix}`) > -1 && fieldModel.$value.length > 0) {
|
if (url.indexOf(`${queryParamPrefix}${fieldModel.name}${queryParamSuffix}`) > -1 && fieldModel.$value.length > 0) {
|
||||||
url = url.replace(`${queryParamPrefix}${fieldModel.name}${queryParamSuffix}`, fieldModel.$value);
|
url = url.replace(`${queryParamPrefix}${fieldModel.name}${queryParamSuffix}`, fieldModel.$value);
|
||||||
}
|
}
|
||||||
|
@ -106,7 +121,6 @@ export class ConsoleViewer extends React.Component<ConsoleViewerProps, ConsoleVi
|
||||||
|
|
||||||
const request = new Request(url, {
|
const request = new Request(url, {
|
||||||
method: endpoint.method,
|
method: endpoint.method,
|
||||||
credentials: 'include',
|
|
||||||
redirect: 'manual',
|
redirect: 'manual',
|
||||||
headers: myHeaders,
|
headers: myHeaders,
|
||||||
body: (body) ? JSON.stringify(body) : undefined,
|
body: (body) ? JSON.stringify(body) : undefined,
|
||||||
|
@ -173,29 +187,4 @@ export class ConsoleViewer extends React.Component<ConsoleViewerProps, ConsoleVi
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSchema() {
|
|
||||||
const { operation } = this.props;
|
|
||||||
const requestBodyContent = operation.requestBody && operation.requestBody.content && operation.requestBody.content;
|
|
||||||
const mediaTypes = (requestBodyContent && requestBodyContent.mediaTypes) ? requestBodyContent.mediaTypes : [];
|
|
||||||
|
|
||||||
if (!mediaTypes.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const schema: Schema = {
|
|
||||||
};
|
|
||||||
for (const mediaType of mediaTypes) {
|
|
||||||
if (mediaType.name.indexOf('json') > -1) {
|
|
||||||
if (mediaType.schema) {
|
|
||||||
schema.rawSchema = mediaType.schema && mediaType.schema.rawSchema;
|
|
||||||
console.log('rawSchema : ' + JSON.stringify(schema));
|
|
||||||
console.log('schema : ' + JSON.stringify(mediaType.schema.schema));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return schema;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,40 @@
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { AppStore } from '../../services';
|
||||||
|
|
||||||
import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation';
|
import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation';
|
||||||
import { AdvancedMarkdown } from '../Markdown/AdvancedMarkdown';
|
import { AdvancedMarkdown } from '../Markdown/AdvancedMarkdown';
|
||||||
|
|
||||||
import { H1, H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements';
|
import { H1, H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements';
|
||||||
import { ContentItemModel } from '../../services/MenuBuilder';
|
import { ContentItemModel } from '../../services/MenuBuilder';
|
||||||
import { GroupModel, OperationModel } from '../../services/models';
|
import { GroupModel } from '../../services/models';
|
||||||
import { Operation } from '../Operation/Operation';
|
import { Operation } from '../Operation/Operation';
|
||||||
|
|
||||||
@observer
|
export interface ContentItemsProps {
|
||||||
export class ContentItems extends React.Component<{
|
|
||||||
items: ContentItemModel[];
|
items: ContentItemModel[];
|
||||||
}> {
|
store: AppStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class ContentItems extends React.Component<ContentItemsProps> {
|
||||||
render() {
|
render() {
|
||||||
const items = this.props.items;
|
const { items, store } = this.props;
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return items.map(item => <ContentItem item={item} key={item.id} />);
|
return items.map(item => <ContentItem store={store} item={item} key={item.id} />);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ContentItemProps {
|
export interface ContentItemProps {
|
||||||
item: ContentItemModel;
|
item: ContentItemModel;
|
||||||
|
store: AppStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class ContentItem extends React.Component<ContentItemProps> {
|
export class ContentItem extends React.Component<ContentItemProps> {
|
||||||
render() {
|
render() {
|
||||||
const item = this.props.item;
|
const { item, store } = this.props;
|
||||||
let content;
|
let content;
|
||||||
const { type } = item;
|
const { type } = item;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -41,7 +46,7 @@ export class ContentItem extends React.Component<ContentItemProps> {
|
||||||
content = <SectionItem {...this.props} />;
|
content = <SectionItem {...this.props} />;
|
||||||
break;
|
break;
|
||||||
case 'operation':
|
case 'operation':
|
||||||
content = <OperationItem item={item as any} />;
|
content = <Operation securitySchemes={store.spec.securitySchemes} operation={item as any} />;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content = <SectionItem {...this.props} />;
|
content = <SectionItem {...this.props} />;
|
||||||
|
@ -54,7 +59,7 @@ export class ContentItem extends React.Component<ContentItemProps> {
|
||||||
{content}
|
{content}
|
||||||
</Section>
|
</Section>
|
||||||
)}
|
)}
|
||||||
{item.items && <ContentItems items={item.items} />}
|
{item.items && <ContentItems store={store} items={item.items} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -90,12 +95,3 @@ export class SectionItem extends React.Component<ContentItemProps> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
|
||||||
export class OperationItem extends React.Component<{
|
|
||||||
item: OperationModel;
|
|
||||||
}> {
|
|
||||||
render() {
|
|
||||||
return <Operation operation={this.props.item} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Badge, DarkRightPanel, H2, MiddlePanel, Row } from '../../common-elemen
|
||||||
|
|
||||||
import { ShareLink } from '../../common-elements/linkify';
|
import { ShareLink } from '../../common-elements/linkify';
|
||||||
|
|
||||||
import { OperationModel as OperationType } from '../../services/models';
|
import { OperationModel as OperationType, SecuritySchemesModel } from '../../services/models';
|
||||||
import styled from '../../styled-components';
|
import styled from '../../styled-components';
|
||||||
import { ConsoleViewer } from '../Console/ConsoleViewer';
|
import { ConsoleViewer } from '../Console/ConsoleViewer';
|
||||||
import { Endpoint } from '../Endpoint/Endpoint';
|
import { Endpoint } from '../Endpoint/Endpoint';
|
||||||
|
@ -34,6 +34,7 @@ const Description = styled.div`
|
||||||
|
|
||||||
export interface OperationProps {
|
export interface OperationProps {
|
||||||
operation: OperationType;
|
operation: OperationType;
|
||||||
|
securitySchemes: SecuritySchemesModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OperationState {
|
export interface OperationState {
|
||||||
|
@ -57,7 +58,7 @@ export class Operation extends React.Component<OperationProps, OperationState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { operation } = this.props;
|
const { operation, securitySchemes } = this.props;
|
||||||
const { executeMode } = this.state;
|
const { executeMode } = this.state;
|
||||||
|
|
||||||
const { name: summary, description, deprecated, externalDocs } = operation;
|
const { name: summary, description, deprecated, externalDocs } = operation;
|
||||||
|
@ -95,7 +96,13 @@ export class Operation extends React.Component<OperationProps, OperationState> {
|
||||||
{!options.pathInMiddlePanel && <Endpoint operation={operation} />}
|
{!options.pathInMiddlePanel && <Endpoint operation={operation} />}
|
||||||
{executeMode &&
|
{executeMode &&
|
||||||
<div>
|
<div>
|
||||||
<ConsoleViewer operation={operation} additionalHeaders={options.additionalHeaders} queryParamPrefix={options.queryParamPrefix} queryParamSuffix={options.queryParamSuffix} />
|
<ConsoleViewer
|
||||||
|
securitySchemes={securitySchemes}
|
||||||
|
operation={operation}
|
||||||
|
additionalHeaders={options.additionalHeaders}
|
||||||
|
queryParamPrefix={options.queryParamPrefix}
|
||||||
|
queryParamSuffix={options.queryParamSuffix}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{!executeMode &&
|
{!executeMode &&
|
||||||
|
|
|
@ -57,7 +57,7 @@ export class Redoc extends React.Component<RedocProps> {
|
||||||
</StickyResponsiveSidebar>
|
</StickyResponsiveSidebar>
|
||||||
<ApiContentWrap className="api-content">
|
<ApiContentWrap className="api-content">
|
||||||
<ApiInfo store={store} />
|
<ApiInfo store={store} />
|
||||||
<ContentItems items={menu.items as any} />
|
<ContentItems store={store} items={menu.items as any} />
|
||||||
</ApiContentWrap>
|
</ApiContentWrap>
|
||||||
<BackgroundStub />
|
<BackgroundStub />
|
||||||
</RedocWrap>
|
</RedocWrap>
|
||||||
|
|
|
@ -67,18 +67,16 @@ export class SecurityRequirement extends React.PureComponent<SecurityRequirement
|
||||||
const security = this.props.security;
|
const security = this.props.security;
|
||||||
return (
|
return (
|
||||||
<SecurityRequirementOrWrap>
|
<SecurityRequirementOrWrap>
|
||||||
{security.schemes.map(scheme => {
|
{security.schemes.map(scheme => (
|
||||||
return (
|
<SecurityRequirementAndWrap key={scheme.id}>
|
||||||
<SecurityRequirementAndWrap key={scheme.id}>
|
<Link to={scheme.sectionId}>{scheme.id}</Link>
|
||||||
<Link to={scheme.sectionId}>{scheme.id}</Link>
|
{scheme.scopes.length > 0 && ' ('}
|
||||||
{scheme.scopes.length > 0 && ' ('}
|
{scheme.scopes.map(scope => (
|
||||||
{scheme.scopes.map(scope => (
|
<ScopeName key={scope}>{scope}</ScopeName>
|
||||||
<ScopeName key={scope}>{scope}</ScopeName>
|
))}
|
||||||
))}
|
{scheme.scopes.length > 0 && ') '}
|
||||||
{scheme.scopes.length > 0 && ') '}
|
</SecurityRequirementAndWrap>
|
||||||
</SecurityRequirementAndWrap>
|
))}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</SecurityRequirementOrWrap>
|
</SecurityRequirementOrWrap>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user