This directory contains scripts that automatically generate OpenAPI specifications from your SvelteKit route structure.
Instead of manually registering every API endpoint, the system:
- Scans your
src/routesdirectory for+server.tsfiles - Converts SvelteKit paths (
[id]) to OpenAPI paths ({id}) - Extracts metadata from route exports
- Generates a complete OpenAPI specification
Each +server.ts file exports an _openapi object that describes its operations:
Note: The export is prefixed with
_to follow SvelteKit conventions (exports must be standard handlers or prefixed with_).
import type { RouteOpenAPIMetadata } from '../../../../scripts/types.js';
import { UserSchema, CreateUserSchema } from '@zod-schema-example/shared';
import { z } from 'zod';
export const _openapi: RouteOpenAPIMetadata = {
operations: [
{
method: 'GET',
summary: 'List all users',
description: 'Get all users in the system',
tags: ['Users'],
responses: [
{
status: 200,
description: 'List of users',
schema: z.array(UserSchema) // Use your Zod schemas!
}
]
},
{
method: 'POST',
summary: 'Create user',
tags: ['Users'],
requestBody: {
schema: CreateUserSchema, // Zod validation!
description: 'User data'
},
responses: [
{
status: 201,
description: 'User created',
schema: UserSchema
},
{
status: 400,
description: 'Invalid input'
}
]
}
]
};
// Your normal SvelteKit handlers...
export const GET: RequestHandler = async () => { /* ... */ };
export const POST: RequestHandler = async () => { /* ... */ };The scanner automatically converts SvelteKit paths to OpenAPI format:
| SvelteKit Path | OpenAPI Path |
|---|---|
src/routes/api/users/+server.ts |
/api/users |
src/routes/api/users/[id]/+server.ts |
/api/users/{id} |
src/routes/api/posts/[postId]/comments/[commentId]/+server.ts |
/api/posts/{postId}/comments/{commentId} |
Run the generator:
npm run generate:openapiThis will:
- Scan all
+server.tsfiles insrc/routes - Extract OpenAPI metadata
- Generate
static/openapi.json
scripts/
├── types.ts # TypeScript types for OpenAPI metadata
├── route-scanner.ts # Scans routes and discovers endpoints
├── generate-openapi.ts # Main generator script
└── README.md # This file
-
Create the route file following SvelteKit conventions:
src/routes/api/products/+server.ts -
Export OpenAPI metadata:
export const _openapi: RouteOpenAPIMetadata = { operations: [ { method: 'GET', summary: 'List products', tags: ['Products'], responses: [/* ... */] } ] };
-
Implement your handlers:
export const GET: RequestHandler = async () => { // Your logic here };
-
Regenerate OpenAPI:
npm run generate:openapi
That's it! No manual registration needed.
✅ Single Source of Truth: Route structure defines API structure ✅ Type Safety: Full TypeScript support with Zod schemas ✅ No Duplication: Define endpoints once in route files ✅ Convention-Based: Follows SvelteKit's file-based routing ✅ Validation: Use the same Zod schemas for validation and documentation ✅ Automatic: New routes are automatically discovered
For routes with path parameters, you can customize the parameter schema:
// In generate-openapi.ts, define custom parameter schemas:
export const ProductIdParamSchema = z.object({
productId: z.string().uuid().openapi({
param: { name: 'productId', in: 'path' }
})
});Then reference it in the generator's parameter detection logic.
Use tags to organize your API documentation:
export const openapi: RouteOpenAPIMetadata = {
operations: [
{
method: 'GET',
tags: ['Products', 'Public'], // Multiple tags
// ...
}
]
};You can specify different response schemas for different status codes:
responses: [
{
status: 200,
description: 'Success',
schema: UserSchema
},
{
status: 404,
description: 'Not found'
// No schema for error responses
}
]Make sure your route file:
- Is named
+server.ts - Exports an
_openapiobject (with the underscore prefix) - Uses the correct
RouteOpenAPIMetadatatype
Check that you're importing types correctly:
import type { RouteOpenAPIMetadata } from '../scripts/types.js';The path will vary based on your route's depth.
Ensure your Zod schemas are extended with OpenAPI:
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
extendZodWithOpenApi(z);This should already be done in your shared schema files.