@gitbook/react-openapi 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/InteractiveSection.d.ts +2 -0
- package/dist/InteractiveSection.js +18 -3
- package/dist/OpenAPICodeSample.js +38 -4
- package/dist/OpenAPIOperation.js +3 -3
- package/dist/OpenAPIResponseExample.js +22 -16
- package/dist/OpenAPIResponses.js +2 -2
- package/dist/OpenAPISchema.js +4 -1
- package/dist/ScalarApiButton.d.ts +4 -1
- package/dist/ScalarApiButton.js +2 -2
- package/dist/code-samples.js +19 -0
- package/dist/generateSchemaExample.js +2 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +8 -2
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +3 -0
- package/package.json +9 -6
- package/src/InteractiveSection.tsx +22 -2
- package/src/OpenAPICodeSample.tsx +50 -8
- package/src/OpenAPIOperation.tsx +5 -3
- package/src/OpenAPIResponseExample.tsx +39 -24
- package/src/OpenAPIResponses.tsx +2 -1
- package/src/OpenAPISchema.tsx +5 -0
- package/src/ScalarApiButton.tsx +5 -2
- package/src/code-samples.ts +19 -0
- package/src/generateSchemaExample.ts +2 -2
- package/src/types.ts +9 -3
- package/src/utils.ts +4 -0
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { CodeSampleInput, codeSampleGenerators } from './code-samples';
|
|
4
4
|
import { OpenAPIOperationData } from './fetchOpenAPIOperation';
|
|
5
|
-
import { generateMediaTypeExample } from './generateSchemaExample';
|
|
5
|
+
import { generateMediaTypeExample, generateSchemaExample } from './generateSchemaExample';
|
|
6
6
|
import { InteractiveSection } from './InteractiveSection';
|
|
7
7
|
import { getServersURL } from './OpenAPIServerURL';
|
|
8
8
|
import { ScalarApiButton } from './ScalarApiButton';
|
|
@@ -19,17 +19,51 @@ export function OpenAPICodeSample(props: {
|
|
|
19
19
|
}) {
|
|
20
20
|
const { data, context } = props;
|
|
21
21
|
|
|
22
|
+
const searchParams = new URLSearchParams();
|
|
23
|
+
const headersObject: { [k: string]: string } = {};
|
|
24
|
+
|
|
25
|
+
data.operation.parameters?.forEach((rawParam) => {
|
|
26
|
+
const param = noReference(rawParam);
|
|
27
|
+
if (!param) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (param.in === 'header' && param.required) {
|
|
32
|
+
const example = param.schema
|
|
33
|
+
? generateSchemaExample(noReference(param.schema))
|
|
34
|
+
: undefined;
|
|
35
|
+
if (example !== undefined) {
|
|
36
|
+
headersObject[param.name] =
|
|
37
|
+
typeof example !== 'string' ? JSON.stringify(example) : example;
|
|
38
|
+
}
|
|
39
|
+
} else if (param.in === 'query' && param.required) {
|
|
40
|
+
const example = param.schema
|
|
41
|
+
? generateSchemaExample(noReference(param.schema))
|
|
42
|
+
: undefined;
|
|
43
|
+
if (example !== undefined) {
|
|
44
|
+
searchParams.append(
|
|
45
|
+
param.name,
|
|
46
|
+
String(Array.isArray(example) ? example[0] : example),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
22
52
|
const requestBody = noReference(data.operation.requestBody);
|
|
23
53
|
const requestBodyContent = requestBody ? Object.entries(requestBody.content)[0] : undefined;
|
|
24
54
|
|
|
25
55
|
const input: CodeSampleInput = {
|
|
26
|
-
url:
|
|
56
|
+
url:
|
|
57
|
+
getServersURL(data.servers) +
|
|
58
|
+
data.path +
|
|
59
|
+
(searchParams.size ? `?${searchParams.toString()}` : ''),
|
|
27
60
|
method: data.method,
|
|
28
61
|
body: requestBodyContent
|
|
29
62
|
? generateMediaTypeExample(requestBodyContent[1], { onlyRequired: true })
|
|
30
63
|
: undefined,
|
|
31
64
|
headers: {
|
|
32
65
|
...getSecurityHeaders(data.securities),
|
|
66
|
+
...headersObject,
|
|
33
67
|
...(requestBodyContent
|
|
34
68
|
? {
|
|
35
69
|
'Content-Type': requestBodyContent[0],
|
|
@@ -53,11 +87,19 @@ export function OpenAPICodeSample(props: {
|
|
|
53
87
|
(['x-custom-examples', 'x-code-samples', 'x-codeSamples'] as const).forEach((key) => {
|
|
54
88
|
const customSamples = data.operation[key];
|
|
55
89
|
if (customSamples && Array.isArray(customSamples)) {
|
|
56
|
-
customCodeSamples = customSamples
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
90
|
+
customCodeSamples = customSamples
|
|
91
|
+
.filter((sample) => {
|
|
92
|
+
return (
|
|
93
|
+
typeof sample.label === 'string' &&
|
|
94
|
+
typeof sample.source === 'string' &&
|
|
95
|
+
typeof sample.lang === 'string'
|
|
96
|
+
);
|
|
97
|
+
})
|
|
98
|
+
.map((sample) => ({
|
|
99
|
+
key: `redocly-${sample.lang}`,
|
|
100
|
+
label: sample.label,
|
|
101
|
+
body: <context.CodeBlock code={sample.source} syntax={sample.lang} />,
|
|
102
|
+
}));
|
|
61
103
|
}
|
|
62
104
|
});
|
|
63
105
|
|
|
@@ -77,7 +119,7 @@ export function OpenAPICodeSample(props: {
|
|
|
77
119
|
tabs={samples}
|
|
78
120
|
overlay={
|
|
79
121
|
data['x-hideTryItPanel'] || data.operation['x-hideTryItPanel'] ? null : (
|
|
80
|
-
<ScalarApiButton />
|
|
122
|
+
<ScalarApiButton method={data.method} path={data.path} />
|
|
81
123
|
)
|
|
82
124
|
}
|
|
83
125
|
/>
|
package/src/OpenAPIOperation.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
|
+
import { ApiClientModalProvider } from '@scalar/api-client-react';
|
|
3
4
|
|
|
4
5
|
import { OpenAPIOperationData, toJSON } from './fetchOpenAPIOperation';
|
|
5
6
|
import { Markdown } from './Markdown';
|
|
@@ -8,7 +9,6 @@ import { OpenAPIResponseExample } from './OpenAPIResponseExample';
|
|
|
8
9
|
import { OpenAPIServerURL } from './OpenAPIServerURL';
|
|
9
10
|
import { OpenAPISpec } from './OpenAPISpec';
|
|
10
11
|
import { OpenAPIClientContext, OpenAPIContextProps } from './types';
|
|
11
|
-
import { ApiClientModalProvider } from '@scalar/api-client-react';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Display an interactive OpenAPI operation.
|
|
@@ -23,8 +23,8 @@ export function OpenAPIOperation(props: {
|
|
|
23
23
|
|
|
24
24
|
const clientContext: OpenAPIClientContext = {
|
|
25
25
|
defaultInteractiveOpened: context.defaultInteractiveOpened,
|
|
26
|
-
specUrl: context.specUrl,
|
|
27
26
|
icons: context.icons,
|
|
27
|
+
blockKey: context.blockKey,
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
return (
|
|
@@ -34,7 +34,9 @@ export function OpenAPIOperation(props: {
|
|
|
34
34
|
>
|
|
35
35
|
<div className={classNames('openapi-operation', className)}>
|
|
36
36
|
<div className="openapi-intro">
|
|
37
|
-
<h2 className="openapi-summary"
|
|
37
|
+
<h2 className="openapi-summary" id={context.id}>
|
|
38
|
+
{operation.summary}
|
|
39
|
+
</h2>
|
|
38
40
|
{operation.description ? (
|
|
39
41
|
<Markdown className="openapi-description" source={operation.description} />
|
|
40
42
|
) : null}
|
|
@@ -3,7 +3,7 @@ import { InteractiveSection } from './InteractiveSection';
|
|
|
3
3
|
import { OpenAPIOperationData } from './fetchOpenAPIOperation';
|
|
4
4
|
import { generateSchemaExample } from './generateSchemaExample';
|
|
5
5
|
import { OpenAPIContextProps } from './types';
|
|
6
|
-
import { noReference } from './utils';
|
|
6
|
+
import { createStateKey, noReference } from './utils';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Display an example of the response content.
|
|
@@ -36,37 +36,52 @@ export function OpenAPIResponseExample(props: {
|
|
|
36
36
|
}
|
|
37
37
|
return Number(a) - Number(b);
|
|
38
38
|
});
|
|
39
|
-
// Take the first one
|
|
40
|
-
const response = responses[0];
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
const examples = responses
|
|
41
|
+
.map((response) => {
|
|
42
|
+
const responseObject = noReference(response[1]);
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
const schema = noReference(
|
|
45
|
+
(
|
|
46
|
+
responseObject.content?.['application/json'] ??
|
|
47
|
+
responseObject.content?.[Object.keys(responseObject.content)[0]]
|
|
48
|
+
)?.schema,
|
|
49
|
+
);
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
responseObject.content?.[Object.keys(responseObject.content)[0]]
|
|
52
|
-
)?.schema,
|
|
53
|
-
);
|
|
51
|
+
if (!schema) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
const example = generateSchemaExample(schema);
|
|
56
|
+
if (example === undefined) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
key: `${response[0]}`,
|
|
62
|
+
label: `${response[0]}`,
|
|
63
|
+
body: (
|
|
64
|
+
<context.CodeBlock
|
|
65
|
+
code={
|
|
66
|
+
typeof example === 'string' ? example : JSON.stringify(example, null, 2)
|
|
67
|
+
}
|
|
68
|
+
syntax="json"
|
|
69
|
+
/>
|
|
70
|
+
),
|
|
71
|
+
};
|
|
72
|
+
})
|
|
73
|
+
.filter((val): val is { key: string; label: string; body: any } => Boolean(val));
|
|
58
74
|
|
|
59
|
-
|
|
60
|
-
if (example === undefined) {
|
|
75
|
+
if (examples.length === 0) {
|
|
61
76
|
return null;
|
|
62
77
|
}
|
|
63
78
|
|
|
64
79
|
return (
|
|
65
|
-
<InteractiveSection
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
80
|
+
<InteractiveSection
|
|
81
|
+
stateKey={createStateKey('response', context.blockKey)}
|
|
82
|
+
header="Response"
|
|
83
|
+
className="openapi-response-example"
|
|
84
|
+
tabs={examples}
|
|
85
|
+
/>
|
|
71
86
|
);
|
|
72
87
|
}
|
package/src/OpenAPIResponses.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { OpenAPIV3 } from 'openapi-types';
|
|
4
|
-
import { noReference } from './utils';
|
|
4
|
+
import { createStateKey, noReference } from './utils';
|
|
5
5
|
import { OpenAPIResponse } from './OpenAPIResponse';
|
|
6
6
|
import { OpenAPIClientContext } from './types';
|
|
7
7
|
import { InteractiveSection } from './InteractiveSection';
|
|
@@ -17,6 +17,7 @@ export function OpenAPIResponses(props: {
|
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
19
|
<InteractiveSection
|
|
20
|
+
stateKey={createStateKey('response', context.blockKey)}
|
|
20
21
|
header="Response"
|
|
21
22
|
className={classNames('openapi-responses')}
|
|
22
23
|
tabs={Object.entries(responses).map(([statusCode, response]) => {
|
package/src/OpenAPISchema.tsx
CHANGED
|
@@ -104,6 +104,11 @@ export function OpenAPISchemaProperty(
|
|
|
104
104
|
Example: <code>{JSON.stringify(schema.example)}</code>
|
|
105
105
|
</span>
|
|
106
106
|
) : null}
|
|
107
|
+
{schema.pattern ? (
|
|
108
|
+
<div className="openapi-schema-pattern">
|
|
109
|
+
Pattern: <code>{schema.pattern}</code>
|
|
110
|
+
</div>
|
|
111
|
+
) : null}
|
|
107
112
|
</div>
|
|
108
113
|
}
|
|
109
114
|
>
|
package/src/ScalarApiButton.tsx
CHANGED
|
@@ -6,12 +6,15 @@ import React from 'react';
|
|
|
6
6
|
/**
|
|
7
7
|
* Button which launches the Scalar API Client
|
|
8
8
|
*/
|
|
9
|
-
export function ScalarApiButton() {
|
|
9
|
+
export function ScalarApiButton({ method, path }: { method: string; path: string }) {
|
|
10
10
|
const client = useApiClientModal();
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
13
|
<div className="scalar scalar-activate">
|
|
14
|
-
<button
|
|
14
|
+
<button
|
|
15
|
+
className="scalar-activate-button"
|
|
16
|
+
onClick={() => client?.open({ method, path })}
|
|
17
|
+
>
|
|
15
18
|
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="12" fill="none">
|
|
16
19
|
<path
|
|
17
20
|
stroke="currentColor"
|
package/src/code-samples.ts
CHANGED
|
@@ -65,6 +65,25 @@ export const codeSampleGenerators: CodeSampleGenerator[] = [
|
|
|
65
65
|
return lines.map((line, index) => (index > 0 ? indent(line, 2) : line)).join(separator);
|
|
66
66
|
},
|
|
67
67
|
},
|
|
68
|
+
{
|
|
69
|
+
id: 'python',
|
|
70
|
+
label: 'Python',
|
|
71
|
+
syntax: 'python',
|
|
72
|
+
generate: ({ method, url, headers, body }) => {
|
|
73
|
+
let code = 'import requests\n\n';
|
|
74
|
+
code += `response = requests.${method.toLowerCase()}(\n`;
|
|
75
|
+
code += indent(`"${url}",\n`, 4);
|
|
76
|
+
if (headers) {
|
|
77
|
+
code += indent(`headers=${JSON.stringify(headers)},\n`, 4);
|
|
78
|
+
}
|
|
79
|
+
if (body) {
|
|
80
|
+
code += indent(`json=${JSON.stringify(body)}\n`, 4);
|
|
81
|
+
}
|
|
82
|
+
code += ')\n';
|
|
83
|
+
code += `data = response.json()`;
|
|
84
|
+
return code;
|
|
85
|
+
},
|
|
86
|
+
},
|
|
68
87
|
];
|
|
69
88
|
|
|
70
89
|
function indent(code: string, spaces: number) {
|
|
@@ -79,7 +79,7 @@ export function generateSchemaExample(
|
|
|
79
79
|
return 'text';
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
if (schema.type === 'number') {
|
|
82
|
+
if (schema.type === 'number' || schema.type === 'integer') {
|
|
83
83
|
return schema.default || 0;
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -104,7 +104,7 @@ export function generateSchemaExample(
|
|
|
104
104
|
|
|
105
105
|
if (schema.properties) {
|
|
106
106
|
const example: { [key: string]: JSONValue } = {};
|
|
107
|
-
const props = onlyRequired ? schema.required ?? [] : Object.keys(schema.properties);
|
|
107
|
+
const props = onlyRequired ? (schema.required ?? []) : Object.keys(schema.properties);
|
|
108
108
|
|
|
109
109
|
for (const key of props) {
|
|
110
110
|
const property = noReference(schema.properties[key]);
|
package/src/types.ts
CHANGED
|
@@ -2,6 +2,9 @@ export type IconComponent = React.ComponentType<{ className?: string }>;
|
|
|
2
2
|
|
|
3
3
|
export interface OpenAPIContextProps extends OpenAPIClientContext {
|
|
4
4
|
CodeBlock: React.ComponentType<{ code: string; syntax: string }>;
|
|
5
|
+
|
|
6
|
+
/** Spec url for the Scalar Api Client */
|
|
7
|
+
specUrl: string;
|
|
5
8
|
}
|
|
6
9
|
|
|
7
10
|
export interface OpenAPIClientContext {
|
|
@@ -10,14 +13,17 @@ export interface OpenAPIClientContext {
|
|
|
10
13
|
chevronRight: React.ReactNode;
|
|
11
14
|
};
|
|
12
15
|
|
|
13
|
-
/** Spec url foor the Scalar Api Client */
|
|
14
|
-
specUrl: string;
|
|
15
|
-
|
|
16
16
|
/**
|
|
17
17
|
* Force all sections to be opened by default.
|
|
18
18
|
* @default false
|
|
19
19
|
*/
|
|
20
20
|
defaultInteractiveOpened?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The key of the block
|
|
23
|
+
*/
|
|
24
|
+
blockKey?: string;
|
|
25
|
+
/** Optional id attached to the OpenAPI Operation heading and used as an anchor */
|
|
26
|
+
id?: string;
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
export interface OpenAPIFetcher {
|