mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 06:31:49 +00:00
* feat(packages/openapi): add feature to show multiple samples per operation * chore: add changesset * feat(packages/openapi): allow specifying a selectedSampleKey and exclusiveSampleKey when using <APIPage> in MDX * fix(packages/openapi): remove shared groupId, which leads to unintended behaviour when showing multiple examples on one page * fix(packages/openapi): also show examples for operations with not request body, cleanup data structure --------- Co-authored-by: Michael Ermer <[email protected]>
This commit is contained in:
co-authored by
Michael Ermer
parent
216708d1b1
commit
cd894b1d7b
@@ -0,0 +1,8 @@
|
||||
---
|
||||
"fumadocs-openapi": patch
|
||||
"docs": minor
|
||||
---
|
||||
|
||||
Feat: support multiple examples in openapi operation #1370
|
||||
|
||||
Adds two new options to the ApiExample renderer "Samples" and "Sample"
|
||||
+28
-1
@@ -67,6 +67,10 @@ paths:
|
||||
examples:
|
||||
default_example:
|
||||
$ref: '#/components/examples/CreateSpecialEventRequestExample'
|
||||
secondary_example:
|
||||
$ref: '#/components/examples/SecondaryCreateSpecialEventRequestExample'
|
||||
tertiary_example:
|
||||
$ref: '#/components/examples/TertiaryCreateSpecialEventRequestExample'
|
||||
responses:
|
||||
'201':
|
||||
description: Created.
|
||||
@@ -464,7 +468,8 @@ components:
|
||||
ticketDate: '2023-09-05'
|
||||
confirmationCode: ticket-event-9c55eg-8v82a
|
||||
CreateSpecialEventRequestExample:
|
||||
summary: Create special event
|
||||
summary: Create special event 1
|
||||
description: Example with no price.
|
||||
value:
|
||||
name: Mermaid Treasure Identification and Analysis
|
||||
location: Under the seaaa 🦀 🎶 🌊.
|
||||
@@ -473,6 +478,28 @@ components:
|
||||
- '2023-09-05'
|
||||
- '2023-09-08'
|
||||
price: 0
|
||||
SecondaryCreateSpecialEventRequestExample:
|
||||
summary: Create special event 2
|
||||
description: Example with a price.
|
||||
value:
|
||||
name: Mermaid Treasure Identification and Analysis
|
||||
location: Under the seaaa 🦀 🎶 🌊.
|
||||
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
|
||||
dates:
|
||||
- '2023-09-05'
|
||||
- '2023-09-08'
|
||||
price: 1234
|
||||
TertiaryCreateSpecialEventRequestExample:
|
||||
summary: Create special event 3 and a dang long title
|
||||
description: Example with a price.
|
||||
value:
|
||||
name: Mermaid Treasure Identification and Analysis
|
||||
location: Under the seaaa 🦀 🎶 🌊.
|
||||
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
|
||||
dates:
|
||||
- '2023-09-05'
|
||||
- '2023-09-08'
|
||||
price: 1234
|
||||
CreateSpecialEventResponseExample:
|
||||
summary: Special event created
|
||||
value:
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { Fragment, type ReactElement, type ReactNode } from 'react';
|
||||
import { generateSample, type EndpointSample } from '@/utils/generate-sample';
|
||||
import {
|
||||
generateSample,
|
||||
type EndpointSample,
|
||||
EndpointSamples,
|
||||
} from '@/utils/generate-sample';
|
||||
import * as CURL from '@/requests/curl';
|
||||
import * as JS from '@/requests/javascript';
|
||||
import * as Go from '@/requests/go';
|
||||
@@ -29,7 +33,10 @@ interface CustomProperty {
|
||||
export interface CodeSample {
|
||||
lang: string;
|
||||
label: string;
|
||||
source: string | ((endpoint: EndpointSample) => string | undefined) | false;
|
||||
source:
|
||||
| string
|
||||
| ((endpoint: EndpointSample, exampleKey: string) => string | undefined)
|
||||
| false;
|
||||
}
|
||||
|
||||
interface CodeSampleCompiled {
|
||||
@@ -45,6 +52,8 @@ export function Operation({
|
||||
ctx,
|
||||
hasHead,
|
||||
headingLevel = 2,
|
||||
selectedSampleKey,
|
||||
exclusiveSampleKey,
|
||||
}: {
|
||||
type?: 'webhook' | 'operation';
|
||||
path: string;
|
||||
@@ -53,6 +62,8 @@ export function Operation({
|
||||
|
||||
hasHead?: boolean;
|
||||
headingLevel?: number;
|
||||
selectedSampleKey?: string;
|
||||
exclusiveSampleKey?: string;
|
||||
}): ReactElement {
|
||||
const body = method.requestBody;
|
||||
const security = method.security ?? ctx.schema.document.security;
|
||||
@@ -227,7 +238,13 @@ export function Operation({
|
||||
return (
|
||||
<ctx.renderer.API>
|
||||
{info}
|
||||
<APIExample method={method} endpoint={endpoint} ctx={ctx} />
|
||||
<APIExample
|
||||
method={method}
|
||||
endpoint={endpoint}
|
||||
ctx={ctx}
|
||||
selectedSampleKey={selectedSampleKey}
|
||||
exclusiveSampleKey={exclusiveSampleKey}
|
||||
/>
|
||||
</ctx.renderer.API>
|
||||
);
|
||||
} else {
|
||||
@@ -262,46 +279,113 @@ async function APIExample({
|
||||
method,
|
||||
endpoint,
|
||||
ctx,
|
||||
selectedSampleKey,
|
||||
exclusiveSampleKey,
|
||||
}: {
|
||||
method: MethodInformation;
|
||||
endpoint: EndpointSample;
|
||||
ctx: RenderContext;
|
||||
selectedSampleKey?: string;
|
||||
exclusiveSampleKey?: string;
|
||||
}) {
|
||||
const renderer = ctx.renderer;
|
||||
const children: ReactNode[] = [];
|
||||
|
||||
const samples = dedupe([
|
||||
...defaultSamples,
|
||||
...(ctx.generateCodeSamples ? await ctx.generateCodeSamples(endpoint) : []),
|
||||
...((method as CustomProperty)['x-codeSamples'] ?? []),
|
||||
]).flatMap<CodeSampleCompiled>((sample) => {
|
||||
if (sample.source === false) return [];
|
||||
// fallback for methods that have no request body, we also want to show examples for
|
||||
const existingSamples: EndpointSamples = endpoint.body?.samples ?? {
|
||||
_default: {},
|
||||
};
|
||||
const samples: Record<
|
||||
string,
|
||||
{ samples: CodeSampleCompiled[]; title: string; description?: string }
|
||||
> = {};
|
||||
for (const exampleKey in existingSamples) {
|
||||
samples[exampleKey] = {
|
||||
title: existingSamples[exampleKey]?.summary ?? exampleKey,
|
||||
description: existingSamples[exampleKey]?.description,
|
||||
samples: dedupe([
|
||||
...defaultSamples,
|
||||
...(ctx.generateCodeSamples
|
||||
? await ctx.generateCodeSamples(endpoint)
|
||||
: []),
|
||||
...((method as CustomProperty)['x-codeSamples'] ?? []),
|
||||
]).flatMap<CodeSampleCompiled>((sample) => {
|
||||
if (sample.source === false) return [];
|
||||
|
||||
const result =
|
||||
typeof sample.source === 'function'
|
||||
? sample.source(endpoint)
|
||||
: sample.source;
|
||||
if (result === undefined) return [];
|
||||
const result =
|
||||
typeof sample.source === 'function'
|
||||
? sample.source(endpoint, exampleKey)
|
||||
: sample.source;
|
||||
if (result === undefined) return [];
|
||||
|
||||
return {
|
||||
...sample,
|
||||
source: result,
|
||||
return {
|
||||
...sample,
|
||||
source: result,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (samples.length > 0) {
|
||||
children.push(
|
||||
<renderer.Requests key="requests" items={samples.map((s) => s.label)}>
|
||||
{samples.map((s) => (
|
||||
<renderer.Request
|
||||
key={s.label}
|
||||
name={s.label}
|
||||
code={s.source}
|
||||
language={s.lang}
|
||||
/>
|
||||
))}
|
||||
</renderer.Requests>,
|
||||
);
|
||||
if (Object.keys(samples).length > 0) {
|
||||
const sampleTabs: ReactNode[] = [];
|
||||
const titles = [];
|
||||
if (
|
||||
(samples && Object.keys(samples).length === 1 && samples['_default']) ||
|
||||
(exclusiveSampleKey && samples[exclusiveSampleKey])
|
||||
) {
|
||||
// if exclusiveSampleKey is present, we don't use tabs
|
||||
// if only the fallback or non described openapi legacy example is present, we don't use tabs
|
||||
const sampleKey = exclusiveSampleKey ?? '_default';
|
||||
children.push(
|
||||
<renderer.Requests
|
||||
key={`requests-${sampleKey}`}
|
||||
items={samples[sampleKey].samples.map((s) => s.label)}
|
||||
>
|
||||
{samples[sampleKey].samples.map((s) => (
|
||||
<renderer.Request
|
||||
key={`requests-${sampleKey}-${s.label}`}
|
||||
name={s.label}
|
||||
code={s.source}
|
||||
language={s.lang}
|
||||
/>
|
||||
))}
|
||||
</renderer.Requests>,
|
||||
);
|
||||
} else {
|
||||
for (const sampleKey in samples) {
|
||||
const title = samples[sampleKey].title;
|
||||
titles.push(title);
|
||||
sampleTabs.push(
|
||||
<renderer.Sample key={sampleKey} value={title}>
|
||||
{samples[sampleKey].description && (
|
||||
<Markdown text={samples[sampleKey].description} />
|
||||
)}
|
||||
<renderer.Requests
|
||||
key={`requests-${sampleKey}`}
|
||||
items={samples[sampleKey].samples.map((s) => s.label)}
|
||||
>
|
||||
{samples[sampleKey].samples.map((s) => (
|
||||
<renderer.Request
|
||||
key={`requests-${sampleKey}-${s.label}`}
|
||||
name={s.label}
|
||||
code={s.source}
|
||||
language={s.lang}
|
||||
/>
|
||||
))}
|
||||
</renderer.Requests>
|
||||
</renderer.Sample>,
|
||||
);
|
||||
}
|
||||
children.push(
|
||||
<renderer.Samples
|
||||
items={titles}
|
||||
key="samples"
|
||||
defaultValue={selectedSampleKey}
|
||||
>
|
||||
{sampleTabs}
|
||||
</renderer.Samples>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
children.push(
|
||||
|
||||
@@ -50,6 +50,16 @@ export interface RequestProps {
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface SampleProps {
|
||||
value: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
export interface SamplesProps {
|
||||
items: string[];
|
||||
children: ReactNode;
|
||||
defaultValue?: string;
|
||||
}
|
||||
|
||||
export interface ResponseTypeProps {
|
||||
lang: string;
|
||||
code: string;
|
||||
@@ -70,6 +80,8 @@ export interface Renderer {
|
||||
|
||||
Responses: ComponentType<ResponsesProps>;
|
||||
Response: ComponentType<ResponseProps>;
|
||||
Sample: ComponentType<SampleProps>;
|
||||
Samples: ComponentType<SamplesProps>;
|
||||
Requests: ComponentType<{ items: string[]; children: ReactNode }>;
|
||||
Request: ComponentType<RequestProps>;
|
||||
ResponseTypes: ComponentType<{ children: ReactNode }>;
|
||||
@@ -132,6 +144,9 @@ export function createRenders(
|
||||
Requests: (props) => (
|
||||
<Tabs groupId="fumadocs_openapi_requests" {...props} />
|
||||
),
|
||||
Samples: (props) => <Tabs {...props} />,
|
||||
Sample: Tab,
|
||||
|
||||
Request: (props) => (
|
||||
<Tab value={props.name}>
|
||||
<CodeBlock
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { type EndpointSample } from '@/utils/generate-sample';
|
||||
import { inputToString } from '@/utils/input-to-string';
|
||||
|
||||
export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
export function getSampleRequest(
|
||||
endpoint: EndpointSample,
|
||||
sampleKey: string,
|
||||
): string {
|
||||
const s: string[] = [];
|
||||
|
||||
s.push(`curl -X ${endpoint.method} "${endpoint.url}"`);
|
||||
@@ -21,7 +24,7 @@ export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
}
|
||||
|
||||
if (endpoint.body?.mediaType === 'multipart/form-data') {
|
||||
const sample = endpoint.body.sample;
|
||||
const sample = endpoint.body.samples[sampleKey]?.value;
|
||||
|
||||
if (sample && typeof sample === 'object') {
|
||||
for (const [key, value] of Object.entries(sample)) {
|
||||
@@ -31,7 +34,7 @@ export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
} else if (endpoint.body) {
|
||||
s.push(`-H "Content-Type: ${endpoint.body.mediaType}"`);
|
||||
s.push(
|
||||
`-d ${inputToString(endpoint.body.sample, endpoint.body.mediaType, 'single-quote')}`,
|
||||
`-d ${inputToString(endpoint.body.samples[sampleKey]?.value ?? '', endpoint.body.mediaType, 'single-quote')}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { type EndpointSample } from '@/utils/generate-sample';
|
||||
import { inputToString } from '@/utils/input-to-string';
|
||||
|
||||
export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
export function getSampleRequest(
|
||||
endpoint: EndpointSample,
|
||||
sampleKey: string,
|
||||
): string {
|
||||
const imports = ['fmt', 'net/http', 'io/ioutil'];
|
||||
const headers = new Map<string, string>();
|
||||
const variables = new Map<string, string>();
|
||||
@@ -28,14 +31,16 @@ export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
|
||||
if (
|
||||
endpoint.body.mediaType === 'multipart/form-data' &&
|
||||
typeof endpoint.body.sample === 'object'
|
||||
typeof endpoint.body.samples[sampleKey]?.value === 'object'
|
||||
) {
|
||||
imports.push('mime/multipart', 'bytes');
|
||||
|
||||
variables.set('payload', `new(bytes.Buffer)`);
|
||||
variables.set('mp', 'multipart.NewWriter(payload)');
|
||||
|
||||
for (const [key, value] of Object.entries(endpoint.body.sample ?? {})) {
|
||||
for (const [key, value] of Object.entries(
|
||||
endpoint.body.samples[sampleKey]?.value ?? {},
|
||||
)) {
|
||||
additional.push(
|
||||
`mp.WriteField("${key}", ${inputToString(value, undefined, 'backtick')})`,
|
||||
);
|
||||
@@ -45,7 +50,7 @@ export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
variables.set(
|
||||
'payload',
|
||||
`strings.NewReader(${inputToString(
|
||||
endpoint.body.sample,
|
||||
endpoint.body.samples[sampleKey]?.value ?? '',
|
||||
endpoint.body.mediaType,
|
||||
'backtick',
|
||||
).replaceAll('\n', '\n ')})`,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { type EndpointSample } from '@/utils/generate-sample';
|
||||
import { inputToString } from '@/utils/input-to-string';
|
||||
|
||||
export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
export function getSampleRequest(
|
||||
endpoint: EndpointSample,
|
||||
sampleKey: string,
|
||||
): string {
|
||||
const s: string[] = [];
|
||||
const options = new Map<string, string>();
|
||||
const headers = new Map<string, unknown>();
|
||||
@@ -38,12 +41,14 @@ export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
|
||||
if (
|
||||
endpoint.body?.mediaType === 'multipart/form-data' &&
|
||||
typeof endpoint.body.sample === 'object' &&
|
||||
endpoint.body.sample
|
||||
typeof endpoint.body.samples[sampleKey]?.value === 'object' &&
|
||||
endpoint.body.samples[sampleKey]?.value
|
||||
) {
|
||||
s.push(`const formData = new FormData();`);
|
||||
|
||||
for (const [key, value] of Object.entries(endpoint.body.sample))
|
||||
for (const [key, value] of Object.entries(
|
||||
endpoint.body.samples[sampleKey]?.value,
|
||||
))
|
||||
s.push(`formData.set(${key}, ${inputToString(value)})`);
|
||||
|
||||
options.set('body', 'formData');
|
||||
@@ -52,16 +57,16 @@ export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
|
||||
if (endpoint.body.mediaType === 'application/json') {
|
||||
code =
|
||||
typeof endpoint.body.sample === 'string'
|
||||
typeof endpoint.body.samples[sampleKey]?.value === 'string'
|
||||
? inputToString(
|
||||
endpoint.body.sample,
|
||||
endpoint.body.samples[sampleKey]?.value,
|
||||
endpoint.body.mediaType,
|
||||
'backtick',
|
||||
)
|
||||
: `JSON.stringify(${JSON.stringify(endpoint.body.sample, null, 2)})`;
|
||||
: `JSON.stringify(${JSON.stringify(endpoint.body.samples[sampleKey]?.value, null, 2)})`;
|
||||
} else {
|
||||
code = inputToString(
|
||||
endpoint.body.sample,
|
||||
endpoint.body.samples[sampleKey]?.value ?? '',
|
||||
endpoint.body.mediaType,
|
||||
'backtick',
|
||||
);
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { type EndpointSample } from '@/utils/generate-sample';
|
||||
import { inputToString } from '@/utils/input-to-string';
|
||||
|
||||
export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
export function getSampleRequest(
|
||||
endpoint: EndpointSample,
|
||||
sampleKey: string,
|
||||
): string {
|
||||
const headers = new Map<string, unknown>();
|
||||
const cookies = new Map<string, unknown>();
|
||||
const variables = new Map<string, string>();
|
||||
@@ -14,11 +17,25 @@ export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
if (endpoint.body) {
|
||||
switch (endpoint.body.mediaType) {
|
||||
case 'application/json':
|
||||
variables.set('json', JSON.stringify(endpoint.body.sample, null, 2));
|
||||
variables.set(
|
||||
'json',
|
||||
JSON.stringify(
|
||||
endpoint.body.samples[sampleKey]?.value ?? {},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 'multipart/form-data':
|
||||
headers.set('Content-Type', endpoint.body.mediaType);
|
||||
variables.set('data', JSON.stringify(endpoint.body.sample, null, 2));
|
||||
variables.set(
|
||||
'data',
|
||||
JSON.stringify(
|
||||
endpoint.body.samples[sampleKey]?.value ?? {},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
headers.set('Content-Type', endpoint.body.mediaType);
|
||||
@@ -26,7 +43,7 @@ export function getSampleRequest(endpoint: EndpointSample): string {
|
||||
variables.set(
|
||||
'data',
|
||||
inputToString(
|
||||
endpoint.body.sample,
|
||||
endpoint.body.samples[sampleKey]?.value ?? '',
|
||||
endpoint.body.mediaType,
|
||||
'backtick',
|
||||
),
|
||||
|
||||
@@ -47,6 +47,14 @@ export interface WebhookItem {
|
||||
export interface OperationItem {
|
||||
path: string;
|
||||
method: OpenAPIV3_1.HttpMethods;
|
||||
/**
|
||||
* The key of the sample to be selected
|
||||
*/
|
||||
selectedSampleKey?: string;
|
||||
/**
|
||||
* Only this sample will be shown
|
||||
*/
|
||||
exclusiveSampleKey?: string;
|
||||
}
|
||||
|
||||
export async function APIPage(props: ApiPageProps) {
|
||||
@@ -79,6 +87,8 @@ export async function APIPage(props: ApiPageProps) {
|
||||
path={item.path}
|
||||
ctx={ctx}
|
||||
hasHead={hasHead}
|
||||
selectedSampleKey={item.selectedSampleKey}
|
||||
exclusiveSampleKey={item.exclusiveSampleKey}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -6,7 +6,14 @@ import {
|
||||
type NoReference,
|
||||
} from '@/utils/schema';
|
||||
import { getSecurities, getSecurityPrefix } from '@/utils/get-security';
|
||||
|
||||
export interface EndpointSamples {
|
||||
[key: string]: {
|
||||
value?: unknown;
|
||||
description?: string;
|
||||
summary?: string;
|
||||
externalValue?: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Sample info of endpoint
|
||||
*/
|
||||
@@ -19,7 +26,7 @@ export interface EndpointSample {
|
||||
body?: {
|
||||
schema: ParsedSchema;
|
||||
mediaType: string;
|
||||
sample: unknown;
|
||||
samples: EndpointSamples;
|
||||
};
|
||||
responses: Record<string, ResponseSample>;
|
||||
parameters: ParameterSample[];
|
||||
@@ -107,7 +114,13 @@ export function generateSample(
|
||||
bodyOutput = {
|
||||
schema,
|
||||
mediaType: type as string,
|
||||
sample: body[type].example ?? generateBody(method.method, schema),
|
||||
samples: body[type].examples
|
||||
? body[type].examples
|
||||
: {
|
||||
_default: {
|
||||
value: body[type].example ?? generateBody(method.method, schema),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -40,27 +40,39 @@ describe('Code Sample Generators', () => {
|
||||
const endpoint = generateSample(path, info, ctx);
|
||||
|
||||
test(`Go: ${method} ${path}`, async () => {
|
||||
await expect(Go.getSampleRequest(endpoint)).toMatchFileSnapshot(
|
||||
`./out/samples/${path}/${method}.go`,
|
||||
);
|
||||
await expect(
|
||||
Go.getSampleRequest(
|
||||
endpoint,
|
||||
Object.keys(endpoint.body?.samples ?? {})[0],
|
||||
),
|
||||
).toMatchFileSnapshot(`./out/samples/${path}/${method}.go`);
|
||||
});
|
||||
|
||||
test(`Curl: ${method} ${path}`, async () => {
|
||||
await expect(Curl.getSampleRequest(endpoint)).toMatchFileSnapshot(
|
||||
`./out/samples/${path}/${method}.bash`,
|
||||
);
|
||||
await expect(
|
||||
Curl.getSampleRequest(
|
||||
endpoint,
|
||||
Object.keys(endpoint.body?.samples ?? {})[0],
|
||||
),
|
||||
).toMatchFileSnapshot(`./out/samples/${path}/${method}.bash`);
|
||||
});
|
||||
|
||||
test(`Python: ${method} ${path}`, async () => {
|
||||
await expect(Python.getSampleRequest(endpoint)).toMatchFileSnapshot(
|
||||
`./out/samples/${path}/${method}.py`,
|
||||
);
|
||||
await expect(
|
||||
Python.getSampleRequest(
|
||||
endpoint,
|
||||
Object.keys(endpoint.body?.samples ?? {})[0],
|
||||
),
|
||||
).toMatchFileSnapshot(`./out/samples/${path}/${method}.py`);
|
||||
});
|
||||
|
||||
test(`JavaScript: ${method} ${path}`, async () => {
|
||||
await expect(JS.getSampleRequest(endpoint)).toMatchFileSnapshot(
|
||||
`./out/samples/${path}/${method}.js`,
|
||||
);
|
||||
await expect(
|
||||
JS.getSampleRequest(
|
||||
endpoint,
|
||||
Object.keys(endpoint.body?.samples ?? {})[0],
|
||||
),
|
||||
).toMatchFileSnapshot(`./out/samples/${path}/${method}.js`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -58,6 +58,8 @@ paths:
|
||||
examples:
|
||||
default_example:
|
||||
$ref: '#/components/examples/CreateSpecialEventRequestExample'
|
||||
seconday_example:
|
||||
$ref: '#/components/examples/SecondaryCreateSpecialEventRequestExample'
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
@@ -454,6 +456,7 @@ components:
|
||||
confirmationCode: ticket-event-9c55eg-8v82a
|
||||
CreateSpecialEventRequestExample:
|
||||
summary: Create special event
|
||||
description: Create a special event for the museum.
|
||||
value:
|
||||
name: Mermaid Treasure Identification and Analysis
|
||||
location: Under the seaaa 🦀 🎶 🌊.
|
||||
@@ -462,6 +465,17 @@ components:
|
||||
- 2023-09-05
|
||||
- 2023-09-08
|
||||
price: 0
|
||||
SecondaryCreateSpecialEventRequestExample:
|
||||
summary: Create special event with price
|
||||
description: Create a special event with a price.
|
||||
value:
|
||||
name: Mermaid Treasure Identification and Analysis
|
||||
location: Under the seaaa 🦀 🎶 🌊.
|
||||
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
|
||||
dates:
|
||||
- 2023-09-05
|
||||
- 2023-09-08
|
||||
price: 1234
|
||||
CreateSpecialEventResponseExample:
|
||||
summary: Special event created
|
||||
value:
|
||||
|
||||
Reference in New Issue
Block a user