Skip to content

Latest commit

 

History

History
225 lines (177 loc) · 5.37 KB

README.md

File metadata and controls

225 lines (177 loc) · 5.37 KB

Automatic OpenAPI Generation from SvelteKit Routes

This directory contains scripts that automatically generate OpenAPI specifications from your SvelteKit route structure.

Overview

Instead of manually registering every API endpoint, the system:

  1. Scans your src/routes directory for +server.ts files
  2. Converts SvelteKit paths ([id]) to OpenAPI paths ({id})
  3. Extracts metadata from route exports
  4. Generates a complete OpenAPI specification

How It Works

1. Route Convention

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 () => { /* ... */ };

2. Path Conversion

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}

3. Generate OpenAPI Spec

Run the generator:

npm run generate:openapi

This will:

  • Scan all +server.ts files in src/routes
  • Extract OpenAPI metadata
  • Generate static/openapi.json

File Structure

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

Adding a New Endpoint

  1. Create the route file following SvelteKit conventions:

    src/routes/api/products/+server.ts
    
  2. Export OpenAPI metadata:

    export const _openapi: RouteOpenAPIMetadata = {
      operations: [
        {
          method: 'GET',
          summary: 'List products',
          tags: ['Products'],
          responses: [/* ... */]
        }
      ]
    };
  3. Implement your handlers:

    export const GET: RequestHandler = async () => {
      // Your logic here
    };
  4. Regenerate OpenAPI:

    npm run generate:openapi

That's it! No manual registration needed.

Benefits

✅ 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

Advanced Usage

Custom Parameter Schemas

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.

Tags and Organization

Use tags to organize your API documentation:

export const openapi: RouteOpenAPIMetadata = {
  operations: [
    {
      method: 'GET',
      tags: ['Products', 'Public'],  // Multiple tags
      // ...
    }
  ]
};

Response Schemas

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
  }
]

Troubleshooting

Route not showing up?

Make sure your route file:

  1. Is named +server.ts
  2. Exports an _openapi object (with the underscore prefix)
  3. Uses the correct RouteOpenAPIMetadata type

Type errors?

Check that you're importing types correctly:

import type { RouteOpenAPIMetadata } from '../scripts/types.js';

The path will vary based on your route's depth.

Schemas not validating?

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.