OpenAPI: Support Java code example

This commit is contained in:
Fuma Nama
2025-06-13 20:18:13 +08:00
parent 7a45921f72
commit 250ab97f9a
8 changed files with 129 additions and 15 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-openapi': patch
---
Support Java code example
+1 -4
View File
@@ -94,10 +94,7 @@ export default async function Page(props: {
<div className="flex flex-row gap-2 items-center mb-8 border-b pb-6">
<LLMCopyButton slug={params.slug} />
<GitHubLink
url={`https://github.com/${owner}/${repo}/blob/dev/${path.relative(
process.cwd(),
page.absolutePath,
)}`}
url={`https://github.com/${owner}/${repo}/blob/dev/apps/docs/content/docs/${page.path}`}
/>
</div>
<div className="prose flex-1 text-fd-foreground/80">
+22 -4
View File
@@ -12,11 +12,18 @@ interface JavaScriptContext {
addImport: (pkg: string, name: string) => void;
}
interface JavaContext {
lang: 'java';
addImport: (specifier: string) => void;
}
export type MediaContext =
| JavaContext
| GoContext
| JavaScriptContext
| {
lang: string;
/**
* Passed by your custom example generator, for your custom media adapter to receive.
*/
@@ -153,11 +160,17 @@ export const defaultAdapters = {
for (const [key, value] of Object.entries(data.body as object)) {
s.push(
`mp.WriteField("${key}", ${inputToString(value, 'json', 'backtick')})`,
`mp.WriteField("${key}", ${inputToString(value, 'json', '`')})`,
);
}
}
if (ctx.lang === 'java' && 'addImport' in ctx) {
ctx.addImport('java.net.http.HttpRequest.BodyPublishers');
s.push(`var body = BodyPublishers.ofByteArray(new byte[] { ... })`);
}
if (s.length > 0) return s.join('\n');
},
},
@@ -181,17 +194,22 @@ function str(
if (format === 'json') {
return `const body = JSON.stringify(${JSON.stringify(init, null, 2)})`;
}
return `const body = ${inputToString(init, format, 'backtick')}`;
return `const body = ${inputToString(init, format, '`')}`;
}
if (ctx.lang === 'python') {
if (format === 'json') return `body = ${JSON.stringify(init, null, 2)}`;
return `body = ${inputToString(init, format, 'python')}`;
return `body = ${inputToString(init, format, '"""')}`;
}
if (ctx.lang === 'go' && 'addImport' in ctx) {
ctx.addImport('strings');
return `body := strings.NewReader(${inputToString(init, format, 'backtick')})`;
return `body := strings.NewReader(${inputToString(init, format, '`')})`;
}
if (ctx.lang === 'java' && 'addImport' in ctx) {
ctx.addImport('java.net.http.HttpRequest.BodyPublishers');
return `var body = BodyPublishers.ofString(${inputToString(init, format, '"""')})`;
}
}
@@ -26,6 +26,10 @@ const defaultSamples: CodeSample[] = [
label: 'Python',
lang: 'python',
},
{
label: 'Java',
lang: 'java',
},
];
interface CustomProperty {
+1 -1
View File
@@ -45,7 +45,7 @@ export const generator: SampleGenerator = (url, data) => {
MediaTypeFormatMap[
data.bodyMediaType as keyof typeof MediaTypeFormatMap
],
'single-quote',
"'",
)}`,
);
}
+6
View File
@@ -3,6 +3,7 @@ import * as CURL from '@/requests/curl';
import * as JS from '@/requests/javascript';
import * as Go from '@/requests/go';
import * as Python from '@/requests/python';
import * as Java from '@/requests/java';
export const defaultSamples: CodeSample[] = [
{
@@ -25,4 +26,9 @@ export const defaultSamples: CodeSample[] = [
source: Python.generator,
lang: 'python',
},
{
label: 'Java',
source: Java.generator,
lang: 'java',
},
];
+88
View File
@@ -0,0 +1,88 @@
'use client';
import { ident, type SampleGenerator } from '@/requests/_shared';
import { resolveRequestData } from '@/utils/url';
export const generator: SampleGenerator = (url, data, { mediaAdapters }) => {
const s: string[] = [];
const headers = { ...data.header };
const imports = new Set<string>([
'java.net.URI',
'java.net.http.HttpClient',
'java.net.http.HttpRequest',
'java.net.http.HttpResponse',
'java.net.http.HttpResponse.BodyHandlers',
'java.time.Duration',
]);
// Handle body if present
let body: string | undefined;
if (data.body && data.bodyMediaType && data.bodyMediaType in mediaAdapters) {
const adapter = mediaAdapters[data.bodyMediaType];
body = adapter.generateExample(data, {
lang: 'java',
addImport: (specifier) => {
imports.add(specifier);
},
});
}
for (const value of imports.values()) {
s.push(`import ${value};`);
}
s.push('');
if (body) {
s.push(body);
}
// Create HttpClient
s.push('HttpClient client = HttpClient.newBuilder()');
s.push(ident('.connectTimeout(Duration.ofSeconds(10))'));
s.push(ident('.build();'));
s.push('');
// Build request
s.push('HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()');
s.push(
ident(`.uri(URI.create(${JSON.stringify(resolveRequestData(url, data))}))`),
);
// Add headers
for (const [key, value] of Object.entries(headers)) {
s.push(ident(`.header(${JSON.stringify(key)}, ${JSON.stringify(value)})`));
}
if (data.bodyMediaType) {
s.push(ident(`.header("Content-Type", "${data.bodyMediaType}")`));
}
// Add cookies if present
const cookieString = Object.entries(data.cookie)
.map(([key, value]) => `${key}=${value}`)
.join('; ');
if (cookieString.length > 0) {
s.push(ident(`.header("Cookie", ${JSON.stringify(cookieString)})`));
}
const arg = body ? 'body' : '';
s.push(ident(`.${data.method.toUpperCase()}(${arg})`));
s.push(ident('.build();'));
s.push('');
// Add response handling
s.push('try {');
s.push(
ident(
'HttpResponse<String> response = client.send(requestBuilder.build(), BodyHandlers.ofString());',
),
);
s.push(ident('System.out.println("Status code: " + response.statusCode());'));
s.push(ident('System.out.println("Response body: " + response.body());'));
s.push('} catch (Exception e) {');
s.push(ident('e.printStackTrace();'));
s.push('}');
return s.join('\n');
};
@@ -7,14 +7,10 @@ import js2xml from 'xml-js/lib/js2xml';
export function inputToString(
value: unknown,
format: 'xml' | 'json' | 'url' | 'ndjson' = 'json',
multiLine: 'single-quote' | 'backtick' | 'python' | 'none' = 'none',
delimit?: string,
): string {
const getStr = (v: string) => {
if (multiLine === 'none') return JSON.stringify(v);
const delimit = { backtick: `\``, 'single-quote': `'`, python: `"""` }[
multiLine
];
if (!delimit) return JSON.stringify(v);
return `${delimit}${v.replaceAll(delimit, `\\${delimit}`)}${delimit}`;
};