Contoh
Contoh praktis yang dapat dijalankan menggunakan API publik. Fungsi konversi bersifat asinkron; gunakan await. Konversi mengurai masukan secara lokal tanpa mengirim permintaan HTTP yang direkam.
1. Perintah curl dasar
Konversi satu perintah curl dan periksa dokumen yang dihasilkan.
import { curlToOpenApi } from "@powerduck/x-to-openapi";
const result = await curlToOpenApi(
`curl -X POST https://api.example.com/users \
-H 'Content-Type: application/json' \
--data '{"name":"Ada","age":36,"tags":["admin","user"]}'`,
);
console.log(result.document.openapi); // "3.2.0"
console.log(result.ok, result.documentValid); // true true
const post = result.document.paths["/users"].post;
const body = post?.requestBody;
if (!body || !("content" in body)) throw new Error("Expected an inline request body");
const media = body.content["application/json"];
console.log(media && "schema" in media ? media.schema : undefined);
// {
// type: "object",
// properties: {
// name: { type: "string" },
// age: { type: "integer" },
// tags: { type: "array", items: { type: "string" } }
// },
// required: ["name", "age", "tags"]
// }
Diagnostik selalu dikembalikan, bahkan saat konversi berhasil:
for (const d of result.diagnostics) {
console.log(`[${d.severity}] ${d.code}: ${d.message}`);
}
2. Beberapa perintah curl dalam batch
Teruskan array perintah atau string berisi beberapa perintah. Permintaan dengan metode dan path yang sama digabungkan; skema digabungkan secara struktural.
import { curlToOpenApi } from "@powerduck/x-to-openapi";
const result = await curlToOpenApi(
[
"curl https://api.example.com/users",
"curl https://api.example.com/users/123",
"curl https://api.example.com/users/456",
`curl -X POST https://api.example.com/users \
-H 'Content-Type: application/json' \
--data '{"name":"Ada"}'`,
],
{
title: "User API",
version: "2.0.0",
useServerBasePath: false,
inferPathParameters: true,
},
);
// The two detail requests are grouped; /users remains a separate path.
console.log(Object.keys(result.document.paths)); // ["/users", "/users/{userId}"]
Keluaran browser “Salin semua sebagai cURL”
Tempel seluruh blok sekaligus: splitCurlCommands menangani tanda kutip, lanjutan baris, prompt, dan curl.exe.
const block = `
$ curl 'https://api.example.com/users/1?active=true'
> curl 'https://api.example.com/users/2' -X POST \
-H 'Content-Type: application/json' --data '{"name":"Ada"}'`;
const result = await curlToOpenApi(block, { title: "Pasted traffic" });
3. Koleksi Postman
Konversi objek koleksi. Folder bertingkat, pewarisan autentikasi, dan skrip pengujian turut diproses.
import { postmanToOpenApi } from "@powerduck/x-to-openapi";
const collection = {
info: {
name: "User API",
schema: "https://schema.postman.com/json/collection/v2.1.0/collection.json",
},
auth: { type: "bearer", bearer: [{ key: "token", value: "{{token}}" }] },
item: [
{
name: "Users",
item: [
{
name: "Create user",
request: {
method: "POST",
url: "https://api.example.com/users",
header: [{ key: "Content-Type", value: "application/json" }],
body: {
mode: "raw",
raw: '{"name":"Ada","role":"admin"}',
options: { raw: { language: "json" } },
},
},
event: [
{
listen: "test",
script: {
type: "text/javascript",
exec: ["pm.test('status is 201', () => pm.response.to.have.status(201));"],
},
},
],
},
],
},
],
};
const result = await postmanToOpenApi(collection, {
title: collection.info.name,
inferPathParameters: true,
});
// Collection-level bearer auth becomes a securityScheme + operation security.
console.log(result.document.components?.securitySchemes);
// { bearerAuth: { type: "http", scheme: "bearer" } }
// The Postman test script is preserved:
console.log(result.document.paths["/users"].post["x-postman-scripts"]);
// { test: "pm.test('status is 201', () => ...)" }
String JSON juga dapat digunakan:
const fromText = await postmanToOpenApi(JSON.stringify(collection));
4. Inferensi parameter path
Saat inferPathParameters aktif, seperti pengaturan bawaan, permintaan dikelompokkan berdasarkan metode, origin, dan bentuk path. Segmen hanya dijadikan parameter jika kelompok memiliki sedikitnya pathParameterMinSamples permintaan, nilainya bervariasi, dan setiap nilai menyerupai pengenal: angka, UUID, ULID, atau string heksadesimal dengan minimal 8 karakter.
import { curlToOpenApi } from "@powerduck/x-to-openapi";
const result = await curlToOpenApi(
[
"curl https://api.example.com/users/123",
"curl https://api.example.com/users/456",
"curl https://api.example.com/users/123/posts/abc12345",
"curl https://api.example.com/users/456/posts/def45678",
],
{ pathParameterMinSamples: 2 },
);
console.log(Object.keys(result.document.paths));
// [ "/users/{userId}", "/users/{userId}/posts/{postId}" ]
Nama parameter berasal dari segmen statis terdekat sebelumnya, diubah ke bentuk tunggal dan camelCase:
| Pola path | Nama parameter |
|---|---|
/users/{} | userId |
/users/{}/posts/{} | userId, postId |
/categories/{}/items/{} | categoryId, itemId |
/{} | param1 |
Nama duplikat dalam satu path mendapat akhiran angka (userId, userId2).
Nonaktifkan inferensi untuk mempertahankan segmen path literal:
await curlToOpenApi(commands, { inferPathParameters: false });
5. Adaptor kustom
Implementasikan SourceAdapter untuk menambahkan sumber seperti HAR, HTTPie, atau Insomnia, lalu daftarkan di XToOpenApi.
import {
XToOpenApi,
CurlAdapter,
type SourceAdapter,
type NormalizedRequest,
type AdapterContext,
} from "@powerduck/x-to-openapi";
// A trivial adapter that emits a single GET request.
class PingAdapter implements SourceAdapter<{ url: string }> {
readonly id = "ping";
canHandle(input: unknown): boolean {
return (
typeof input === "object" &&
input !== null &&
"url" in (input as Record<string, unknown>)
);
}
async parse(
input: { url: string },
context: AdapterContext,
): Promise<NormalizedRequest[]> {
let url: URL;
try {
url = new URL(input.url);
} catch (cause) {
context.report({
code: "ADAPTER_PARSE_FAILED",
severity: "error",
source: this.id,
message: `Invalid URL: ${input.url}`,
cause,
});
return [];
}
return [
{
source: this.id,
sourceIndex: 0,
method: "get",
url,
urlString: url.toString(),
headers: [],
query: [],
cookies: [],
},
];
}
}
const converter = new XToOpenApi()
.register(new PingAdapter())
.register(new CurlAdapter());
// Explicit adapter id:
const a = await converter.convert("ping", { url: "https://api.example.com/health" });
// Auto-detect:
const b = await converter.convert("auto", { url: "https://api.example.com/health" });
console.log(a.document.paths["/health"]?.get?.operationId);
6. Penanganan galat dan mode ketat
Masalah dikumpulkan dalam result.diagnostics. Dengan strict: true, diagnostik tingkat galat melempar ConversionError; peringatan saja tidak. Opsi tidak valid dan ID adaptor tidak dikenal juga dapat melempar pengecualian.
import { curlToOpenApi, ConversionError } from "@powerduck/x-to-openapi";
// Soft mode: inspect diagnostics yourself.
const soft = await curlToOpenApi("curl https://api.example.com/health");
if (!soft.ok) {
for (const d of soft.diagnostics) {
console.error(`[${d.severity}] ${d.code}: ${d.message}`);
}
}
// Strict mode: throw on the first error-severity diagnostic.
try {
await curlToOpenApi("not a curl command at all", { strict: true });
} catch (error) {
if (error instanceof ConversionError) {
console.error("Conversion failed:", error.message);
for (const d of error.diagnostics) console.error(` ${d.code}`);
}
}
Pemeriksaan ukuran saat ini melempar ConversionError jika string, atau total elemen string dalam array, melebihi 10 × 1024 × 1024 unit kode string JavaScript, terlepas dari strict. Ini bukan batas byte UTF-8 dan tidak mengukur objek yang sudah diurai; terapkan batas byte sendiri sebelum menerima masukan yang tidak tepercaya.
Langkah berikutnya
- Referensi API: nilai bawaan opsi dan kode diagnostik.
- Panduan cepat: konversi lengkap pertama Anda.