@minimajs/openapi
v0.3.0
Published
OpenAPI 3.1 specification generator for MinimaJS with Zod schema integration
Downloads
157
Maintainers
Readme
@minimajs/openapi
OpenAPI 3.1 specification generator for MinimaJS with Zod schema integration.
Installation
bun add @minimajs/openapi @minimajs/schema zodFeatures
- Generate OpenAPI 3.1 specification automatically from your routes
- Zod schema integration via
@minimajs/schema - Automatic path parameter extraction
- Support for query parameters, headers, and request bodies
- Multiple response status codes
- Security scheme definitions
- Tags and operation metadata
Usage
import { createApp } from "@minimajs/server/bun";
import { openapi } from "@minimajs/openapi";
import { schema, createBody, createResponse } from "@minimajs/schema";
import { z } from "zod";
const app = createApp();
app.register(
openapi({
info: {
title: "My API",
version: "1.0.0",
},
})
);
// The OpenAPI specification will be available at /openapi.jsonCustom OpenAPI Endpoint Path
app.register(
openapi({
path: "/api/spec.json",
info: {
title: "My API",
version: "1.0.0",
},
})
);Route Documentation
Use @minimajs/schema to define request/response schemas that automatically appear in the OpenAPI spec.
Request Body
import { schema, createBody, createResponse } from "@minimajs/schema";
import { z } from "zod";
const userBody = createBody(
z.object({
name: z.string().min(1),
email: z.string().email(),
})
);
const userResponse = createResponse(
201,
z.object({
id: z.string().uuid(),
name: z.string(),
email: z.string(),
})
);
app.post("/users", schema(userBody, userResponse), () => {
const { name, email } = userBody();
return { id: crypto.randomUUID(), name, email };
});Query Parameters
import { createSearchParams, createResponse, schema } from "@minimajs/schema";
const queryParams = createSearchParams({
page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(10),
search: z.string().optional(),
});
const listResponse = createResponse(
z.array(
z.object({
id: z.string(),
name: z.string(),
})
)
);
app.get("/users", schema(queryParams, listResponse), () => {
const { page, limit, search } = queryParams();
// Handler logic
return [];
});Headers
import { createHeaders, schema } from "@minimajs/schema";
const authHeaders = createHeaders({
authorization: z.string(),
"x-api-key": z.string().optional(),
});
app.get("/protected", schema(authHeaders), () => {
const { authorization } = authHeaders();
// Handler logic
return { message: "Success" };
});Multiple Response Status Codes
const successResponse = createResponse(
200,
z.object({ data: z.string() })
);
const errorResponse = createResponse(
400,
z.object({ error: z.string() })
);
const notFoundResponse = createResponse(
404,
z.object({ message: z.string() })
);
app.get(
"/resource/:id",
schema(successResponse, errorResponse, notFoundResponse),
() => {
// Handler logic
return { data: "ok" };
}
);Response Headers
import { createResponseHeaders, createResponse, schema } from "@minimajs/schema";
const downloadResponse = createResponse(z.string());
const downloadHeaders = createResponseHeaders({
"content-type": z.string(),
"content-disposition": z.string(),
});
app.get("/download", schema(downloadResponse, downloadHeaders), () => {
// Handler logic
return "file content";
});Route Descriptors
describe() - Operation Metadata
Add OpenAPI operation metadata (summary, description, tags, etc.) to individual routes:
import { describe } from "@minimajs/openapi";
app.get("/users", describe({
summary: "List all users",
description: "Returns a paginated list of all users.",
tags: ["Users"],
operationId: "listUsers",
}), () => {
return getUsers();
});
app.post("/users", describe({
summary: "Create a user",
tags: ["Users"],
}), () => {
return createUser();
});
// Mark endpoint as deprecated
app.get("/v1/users", describe({ deprecated: true }), () => {
return legacyGetUsers();
});Combining describe() with schema()
Use both for complete API documentation:
import { describe } from "@minimajs/openapi";
import { schema, createBody, createResponse } from "@minimajs/schema";
app.post(
"/users",
describe({
summary: "Create a new user",
tags: ["Users"],
}),
schema(CreateUserBody, UserResponse),
() => {
const body = CreateUserBody();
return UserResponse({ id: "123", ...body });
}
);internal() - Exclude from OpenAPI
Mark routes as internal to exclude them from the generated specification:
import { internal } from "@minimajs/openapi";
// Health check - not in API docs
app.get("/health", internal(), () => "ok");
// Metrics endpoint - internal only
app.get("/metrics", internal(), () => getMetrics());Module-Level Descriptors
Use the descriptor() plugin to apply metadata to all routes in a module:
import { descriptor } from "@minimajs/server/plugins";
import { describe } from "@minimajs/openapi";
export const meta = {
plugins: [
// All routes in this module tagged with "Users"
descriptor(describe({ tags: ["Users"] })),
],
};
export default async function (app) {
app.get("/", () => getUsers()); // Tagged: Users
app.post("/", () => createUser()); // Tagged: Users
app.get("/:id", () => getUser()); // Tagged: Users
}Multiple descriptors can be passed at once:
const kAdminOnly = Symbol("admin");
export const meta = {
plugins: [
descriptor(
describe({ tags: ["Admin"], security: [{ bearerAuth: [] }] }),
[kAdminOnly, true]
),
],
};OpenAPI Configuration
Tags
app.register(
openapi({
info: {
title: "My API",
version: "1.0.0",
},
tags: [
{
name: "users",
description: "User management operations",
},
{
name: "products",
description: "Product catalog operations",
},
],
})
);Security Schemes
app.register(
openapi({
info: {
title: "My API",
version: "1.0.0",
},
components: {
securitySchemes: {
bearerAuth: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
},
apiKey: {
type: "apiKey",
in: "header",
name: "X-API-Key",
},
},
},
security: [{ bearerAuth: [] }],
})
);Servers
app.register(
openapi({
info: {
title: "My API",
version: "1.0.0",
},
servers: [
{
url: "https://api.example.com",
description: "Production",
},
{
url: "https://staging-api.example.com",
description: "Staging",
},
{
url: "http://localhost:3000",
description: "Development",
},
],
})
);Full Configuration
app.register(
openapi({
info: {
title: "My API",
version: "2.0.0",
description: "Complete API documentation",
termsOfService: "https://example.com/terms",
contact: {
name: "API Support",
url: "https://example.com/support",
email: "[email protected]",
},
license: {
name: "MIT",
url: "https://opensource.org/licenses/MIT",
},
},
servers: [
{ url: "https://api.example.com", description: "Production" },
],
tags: [
{ name: "users", description: "User operations" },
],
externalDocs: {
description: "Full documentation",
url: "https://docs.example.com",
},
})
);API Reference
openapi(options)
Creates an OpenAPI plugin for your MinimaJS application.
Options
| Option | Type | Description |
|--------|------|-------------|
| info | object | Required. API title, version, description, contact, license |
| path | string | OpenAPI spec endpoint path (default: /openapi.json) |
| servers | array | Server configurations |
| tags | array | Tag definitions |
| security | array | Global security requirements |
| components | object | OpenAPI components (schemas, security schemes) |
| externalDocs | object | External documentation link |
generateOpenAPIDocument(app, options)
Generate the OpenAPI document programmatically without registering an endpoint.
import { generateOpenAPIDocument } from "@minimajs/openapi";
const spec = generateOpenAPIDocument(app, {
info: { title: "My API", version: "1.0.0" },
});describe(options)
Creates a route descriptor that adds OpenAPI operation metadata.
import { describe } from "@minimajs/openapi";
describe({
summary: "Short description",
description: "Detailed description with **markdown** support",
tags: ["Tag1", "Tag2"],
operationId: "uniqueOperationId",
deprecated: false,
security: [{ bearerAuth: [] }],
externalDocs: { url: "https://docs.example.com" },
});internal()
Creates a route descriptor that excludes the route from OpenAPI generation.
import { internal } from "@minimajs/openapi";
app.get("/health", internal(), () => "ok");License
MIT
