-
Notifications
You must be signed in to change notification settings - Fork 20
Description
Summary
Automatically infer and generate OpenAPI response schemas by analyzing the actual return type of Next.js route handler functions, eliminating the need for explicit @response JSDoc annotations.
Motivation
Currently, next-openapi-gen requires developers to manually specify response types using JSDoc comments:
/**
* Get post by ID
* @response PostResponseSchema // ← Manual annotation required
* @openapi
*/
export async function GET(request: NextRequest) {
const post = {
id: 1,
title: "My Post",
slug: "my-post",
published: true,
};
return NextResponse.json(post);
}This approach has several limitations:
- Duplication of Truth: The actual response structure is defined in the function body, but we must also manually specify a separate schema
- Maintenance Burden: When the response structure changes, developers must remember to update both the implementation AND the JSDoc annotation
- Type Safety Gap: There's no compile-time guarantee that the @response annotation matches what the function actually returns
- Verbosity: Simple endpoints require extra boilerplate just for documentation
Proposed Solution
Automatically infer response types from the route handler's return type by analyzing:
- Direct NextResponse.json() calls with inline objects or variables
- Function return type annotations (e.g., Promise<NextResponse>)
- TypeScript type inference from return statements
Example 1: Direct Inference from Return Value
/**
* Get post by ID
* @openapi
*/
export async function GET(request: NextRequest) {
const post = {
id: 1,
title: "My Post",
slug: "my-post",
published: true,
};
return NextResponse.json(post);
}Example 2: Inference from Function Return Type
type PostResponse = {
id: number;
title: string;
slug: string;
published: boolean;
};
/**
* Get post by ID
* @openapi
*/
export async function GET(
request: NextRequest
): Promise<NextResponse<PostResponse>> {
// Implementation...
return NextResponse.json(post);
}Example 3: Mixed Approach (Backwards Compatible)
/**
* Get post by ID
* @response PostResponseSchema // ← Explicit annotation takes precedence
* @openapi
*/
export async function GET(request: NextRequest) {
return NextResponse.json(post);
}If @response is explicitly provided, use it (backwards compatible). Otherwise, attempt auto-inference.
Configuration Options
Add new configuration to next.openapi.json:
Benefits
✅ Reduced Boilerplate: No need to write @response for simple endpoints
✅ Single Source of Truth: Response type is derived from actual implementation
✅ Type Safety: Auto-synced with TypeScript types
✅ Better DX: Less manual work, fewer errors
✅ Gradual Adoption: Backwards compatible with existing @response annotations
✅ Maintenance: Response schemas automatically update when code changes
Use Cases
-
Simple CRUD Operations
export async function GET() { return NextResponse.json({ message: "Hello World" }); } // Auto-generates: { message: string }
-
Database Query Results
export async function GET() { const users = await db.select().from(usersTable); return NextResponse.json(users); } // Auto-generates schema from Drizzle/Prisma types
-
Typed Responses
export async function GET(): Promise<NextResponse<User[]>> { const users = await getUsers(); return NextResponse.json(users); } // Auto-generates schema from User[] type
-
Error Responses (Union Types)
export async function GET() { if (error) { return NextResponse.json({ error: "Not found" }, { status: 404 }); } return NextResponse.json({ data: post }); } // Auto-generates schemas for both success and error cases
{ "inferResponses": true, // Enable automatic response inference (default: false for backwards compatibility) "inferredSchemaPrefix": "Auto", // Prefix for auto-generated schema names "preferInferredResponses": false // If true, prefer inferred over @response annotation }