OpenAPI: Support generating custom code examples

This commit is contained in:
fuma-nama
2024-06-29 12:41:07 +08:00
parent cf852f6365
commit 0e420cb4d0
6 changed files with 76 additions and 13 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-openapi': minor
---
Support generating custom code examples
+7 -1
View File
@@ -2,9 +2,10 @@ import Parser from '@apidevtools/json-schema-ref-parser';
import type { OpenAPIV3 as OpenAPI } from 'openapi-types';
import { buildRoutes } from '@/build-routes';
import { renderPage } from '@/render/page';
import type { Endpoint } from '@/endpoint';
import type { RenderContext } from './types';
import { defaultRenderer, type Renderer } from './render/renderer';
import { renderOperation } from './render/operation';
import { type CodeSample, renderOperation } from './render/operation';
export interface GenerateOptions {
/**
@@ -27,6 +28,11 @@ export interface GenerateOptions {
description: string | undefined,
) => Record<string, unknown>;
/**
* Generate code samples for endpoint
*/
generateCodeSamples?: (endpoint: Endpoint) => CodeSample[];
renderer?: Partial<Renderer>;
}
+47 -11
View File
@@ -9,6 +9,16 @@ import { getTypescriptSchema } from '@/utils/get-typescript-schema';
import { heading, p } from './element';
import { schemaElement } from './schema';
interface CustomProperty {
'x-codeSamples'?: CodeSample[];
}
export interface CodeSample {
lang: string;
label: string;
source: string;
}
export async function renderOperation(
path: string,
method: MethodInformation,
@@ -95,21 +105,31 @@ export async function renderOperation(
info.push(getResponseTable(method));
const samples: CodeSample[] = dedupe([
{
label: 'cURL',
source: CURL.getSampleRequest(endpoint),
lang: 'bash',
},
{
label: 'JavaScript',
source: JS.getSampleRequest(endpoint),
lang: 'js',
},
...(ctx.generateCodeSamples?.(endpoint) ?? []),
...((method as CustomProperty)['x-codeSamples'] ?? []),
]);
example.push(
ctx.renderer.Requests(
['cURL', 'JavaScript'],
[
samples.map((s) => s.label),
samples.map((s) =>
ctx.renderer.Request({
name: 'cURL',
code: CURL.getSampleRequest(endpoint),
language: 'bash',
name: s.label,
code: s.source,
language: s.lang,
}),
ctx.renderer.Request({
name: 'JavaScript',
code: JS.getSampleRequest(endpoint),
language: 'js',
}),
],
),
),
);
@@ -121,6 +141,22 @@ export async function renderOperation(
]);
}
/**
* Remove duplicated labels
*/
function dedupe(samples: CodeSample[]): CodeSample[] {
const set = new Set<string>();
const out: CodeSample[] = [];
for (let i = samples.length - 1; i >= 0; i--) {
if (set.has(samples[i].label)) continue;
set.add(samples[i].label);
out.unshift(samples[i]);
}
return out;
}
function getAuthSection(
requirements: OpenAPI.SecurityRequirementObject[],
{ document, renderer }: RenderContext,
+3
View File
@@ -1,5 +1,7 @@
import type { OpenAPIV3 as OpenAPI } from 'openapi-types';
import { type Renderer } from '@/render/renderer';
import type { Endpoint } from '@/endpoint';
import type { CodeSample } from '@/render/operation';
export interface RouteInformation {
path: string;
@@ -17,4 +19,5 @@ export interface RenderContext {
renderer: Renderer;
document: OpenAPI.Document;
baseUrl: string;
generateCodeSamples?: (endpoint: Endpoint) => CodeSample[];
}
+5
View File
@@ -14,6 +14,11 @@ servers:
paths:
/museum-hours:
get:
x-codeSamples:
- lang: bash
label: List all unwatered plants
source: |
planter list -u
summary: Get museum hours
description: Get upcoming museum operating hours
operationId: getMuseumHours
@@ -68,7 +68,7 @@ The number of days per page.
<APIExample>
<Requests items={["cURL","JavaScript"]}>
<Requests items={["cURL","JavaScript","List all unwatered plants"]}>
<Request value={"cURL"}>
@@ -88,6 +88,14 @@ fetch("https://api.fake-museum-example.com/v1/museum-hours?startDate=2023-02-23&
</Request>
<Request value={"List all unwatered plants"}>
```bash
planter list -u
```
</Request>
</Requests>
<Responses items={["200"]}>