Features
Docs
CLI
Benchmarks
Examples

© 2024 MoroJs

OpenAPI Documentation

Automatic OpenAPI 3.0 specification generation from Zod schemas with interactive Swagger UI documentation.

Zero Configuration Documentation

OpenAPI Documentation

Automatic OpenAPI specs from Zod schemas. Interactive Swagger UI. Zero configuration needed.

Documentation That Just Works

Generate OpenAPI specs automatically from your Zod schemas.
Interactive Swagger UI included. Zero configuration.

It's This Simple

Enable documentation with one call

typescript

1import { createApp, z } from '@morojs/moro';
2
3const app = createApp();
4
5// Define your API routes with validation
6app.post('/users')
7  .body(z.object({
8    name: z.string().min(2),
9    email: z.string().email()
10  }))
11  .describe('Create a new user')
12  .tag('users')
13  .handler((req, res) => {
14    return { success: true, data: req.body };
15  });
16
17// Enable documentation
18app.enableDocs({
19  title: 'My API',
20  version: '1.0.0',
21  description: 'API documentation',
22  basePath: '/docs'
23});
24
25app.listen(3000);
26// Visit http://localhost:3000/docs for interactive documentation

Why OpenAPI Documentation Matters

Without automatic documentation, you're manually writing specs that get out of sync. With MoroJS, your docs are always up to date.

Traditional OpenAPI setup requires manual spec writing and constant updates. We generate it automatically from your code.

Without Auto-Docs

  • Manual spec writing
  • Docs get out of sync
  • No interactive UI
  • Time-consuming maintenance

With MoroJS

  • Automatic spec generation
  • Always in sync with code
  • Interactive Swagger UI
  • Zero maintenance

It's This Easy

Add descriptions and tags to routes. Documentation updates automatically.

Add descriptions and tags

typescript

1// .describe() - Add description to your route
2app.get('/users/:id')
3  .describe('Get user by ID')
4  .tag('users', 'read')
5  .handler((req, res) => {
6    // handler code
7  });
8
9// .tag() - Group related endpoints
10app.post('/users')
11  .tag('users', 'create')
12  .describe('Create a new user')
13  .handler((req, res) => {
14    // handler code
15  });

Why It Makes Sense

Automatic

OpenAPI specs generated automatically from Zod schemas

Interactive

Built-in Swagger UI with Try It Out functionality

Type Safe

Full TypeScript inference from schemas to docs

Standards

OpenAPI 3.0 specification with JSON/YAML export

How It Works

MoroJS automatically generates OpenAPI specifications from your Zod schemas and route definitions. When you define routes with validation, descriptions, and tags, the OpenAPI spec is built automatically. The interactive Swagger UI is available at the configured base path.

Configuration Options

Full Configuration Example

typescript

1app.enableDocs({
2  // Required fields
3  title: 'User Management API',
4  version: '1.0.0',
5  
6  // Optional fields
7  description: 'Complete API for user management with authentication',
8  basePath: '/docs',  // Default: '/docs'
9  
10  // Multiple server environments
11  servers: [
12    { url: 'http://localhost:3000', description: 'Development' },
13    { url: 'https://staging.example.com', description: 'Staging' },
14    { url: 'https://api.example.com', description: 'Production' }
15  ],
16  
17  // Contact information
18  contact: {
19    name: 'API Support Team',
20    email: 'support@example.com',
21    url: 'https://example.com/support'
22  },
23  
24  // License information
25  license: {
26    name: 'MIT',
27    url: 'https://opensource.org/licenses/MIT'
28  },
29  
30  // Swagger UI customization
31  swaggerUI: {
32    title: 'My API - Interactive Documentation',
33    enableTryItOut: true,    // Enable "Try it out" button
34    enableFilter: true,       // Enable filter/search
35    enableDeepLinking: true   // Enable deep linking to operations
36  },
37  
38  // Additional options
39  includeExamples: true,     // Include request/response examples
40  includeSchemas: true,      // Include schema definitions
41  enableAuth: true           // Include authentication docs
42});

Automatic Schema Documentation

typescript

1const UserSchema = z.object({
2  name: z.string().min(2).max(50),
3  email: z.string().email(),
4  age: z.number().min(18).optional(),
5  role: z.enum(['admin', 'user', 'moderator']).default('user')
6});
7
8// Schemas are automatically converted to OpenAPI format
9app.post('/users')
10  .body(UserSchema)           // Automatically documented
11  .describe('Create a new user')
12  .tag('users')
13  .handler((req, res) => {
14    return { success: true, data: req.body };
15  });

Query Parameters Documentation

typescript

1app.get('/users')
2  .query(z.object({
3    limit: z.coerce.number().min(1).max(100).default(10),
4    offset: z.coerce.number().min(0).default(0),
5    search: z.string().optional(),
6    role: z.enum(['admin', 'user']).optional()
7  }))
8  .describe('Get users with pagination and filtering')
9  .tag('users')
10  .handler((req, res) => {
11    // Fully typed query parameters
12    const { limit, offset, search, role } = req.query;
13    // handler code
14  });

Advanced Features

Path Parameters Documentation

typescript

1app.get('/users/:id')
2  .params(z.object({
3    id: z.string().uuid('Invalid user ID format')
4  }))
5  .describe('Get user by UUID')
6  .tag('users')
7  .handler((req, res) => {
8    // Fully typed path parameters
9    const userId = req.params.id;
10    // handler code
11  });

Headers Documentation

typescript

1app.get('/api/data')
2  .headers(z.object({
3    'x-api-key': z.string(),
4    'x-request-id': z.string().uuid().optional()
5  }))
6  .describe('Get protected data')
7  .tag('api')
8  .handler((req, res) => {
9    // Fully typed headers
10    const apiKey = req.headers['x-api-key'];
11    // handler code
12  });

Complex Nested Schemas

typescript

1const PostSchema = z.object({
2  title: z.string().min(5).max(200),
3  content: z.string().min(10),
4  author: z.object({
5    id: z.string().uuid(),
6    name: z.string().min(2)
7  }),
8  tags: z.array(z.string()).min(1).max(10),
9  metadata: z.object({
10    category: z.enum(['tech', 'lifestyle', 'business']),
11    publishAt: z.string().datetime().optional(),
12    featured: z.boolean().default(false)
13  }),
14  settings: z.object({
15    allowComments: z.boolean().default(true),
16    visibility: z.enum(['public', 'private', 'draft'])
17  }).optional()
18});
19
20app.post('/posts')
21  .body(PostSchema)
22  .describe('Create post with complex validation')
23  .tag('posts')
24  .handler((req, res) => {
25    return { success: true, data: req.body };
26  });

Programmatic Access to OpenAPI Spec

typescript

1// Get OpenAPI spec as object
2app.get('/api/openapi.json', (req, res) => {
3  res.setHeader('Content-Type', 'application/json');
4  return app.getOpenAPISpec();
5});
6
7// Get OpenAPI spec as YAML
8app.get('/api/openapi.yaml', (req, res) => {
9  res.setHeader('Content-Type', 'text/yaml');
10  res.send(app.getDocsYAML());
11});
12
13// Get OpenAPI spec as JSON string
14app.get('/api/docs.json', (req, res) => {
15  res.setHeader('Content-Type', 'application/json');
16  res.send(app.getDocsJSON());
17});

Complete Example

Full API with Automatic Documentation

typescript

1import { createApp, z } from '@morojs/moro';
2
3const app = createApp();
4
5// Define schemas
6const UserSchema = z.object({
7  name: z.string().min(2).max(50),
8  email: z.string().email(),
9  age: z.number().min(18).optional(),
10  role: z.enum(['admin', 'user']).default('user')
11});
12
13const UserParamsSchema = z.object({
14  id: z.string().uuid()
15});
16
17const UserQuerySchema = z.object({
18  limit: z.coerce.number().min(1).max(100).default(10),
19  offset: z.coerce.number().min(0).default(0),
20  search: z.string().optional()
21});
22
23// Create user
24app.post('/users')
25  .body(UserSchema)
26  .rateLimit({ requests: 20, window: 60000 })
27  .describe('Create a new user')
28  .tag('users', 'create')
29  .handler((req, res) => {
30    res.status(201);
31    return { success: true, data: req.body };
32  });
33
34// List users
35app.get('/users')
36  .query(UserQuerySchema)
37  .cache({ ttl: 60 })
38  .describe('Get users with pagination')
39  .tag('users', 'list')
40  .handler((req, res) => {
41    return {
42      success: true,
43      data: [],
44      pagination: {
45        limit: req.query.limit,
46        offset: req.query.offset
47      }
48    };
49  });
50
51// Get user by ID
52app.get('/users/:id')
53  .params(UserParamsSchema)
54  .describe('Get user by UUID')
55  .tag('users', 'detail')
56  .handler((req, res) => {
57    return {
58      success: true,
59      data: { id: req.params.id }
60    };
61  });
62
63// Update user
64app.put('/users/:id')
65  .params(UserParamsSchema)
66  .body(UserSchema.partial())
67  .auth({ roles: ['admin', 'user'] })
68  .describe('Update user (requires auth)')
69  .tag('users', 'update')
70  .handler((req, res) => {
71    return {
72      success: true,
73      data: { id: req.params.id, ...req.body }
74    };
75  });
76
77// Delete user
78app.delete('/users/:id')
79  .params(UserParamsSchema)
80  .auth({ roles: ['admin'] })
81  .describe('Delete user (admin only)')
82  .tag('users', 'delete', 'admin')
83  .handler((req, res) => {
84    return { success: true };
85  });
86
87// Enable comprehensive documentation
88app.enableDocs({
89  title: 'User Management API',
90  version: '1.0.0',
91  description: 'Complete API with authentication and validation',
92  basePath: '/docs',
93  servers: [
94    { url: 'http://localhost:3000', description: 'Development' },
95    { url: 'https://api.example.com', description: 'Production' }
96  ],
97  contact: {
98    name: 'API Support',
99    email: 'support@example.com'
100  },
101  license: {
102    name: 'MIT',
103    url: 'https://opensource.org/licenses/MIT'
104  },
105  swaggerUI: {
106    enableTryItOut: true,
107    enableFilter: true,
108    enableDeepLinking: true
109  }
110});
111
112app.listen(3000, () => {
113  console.log('Server: http://localhost:3000');
114  console.log('Docs: http://localhost:3000/docs');
115});

Accessing Documentation

Interactive UI

Swagger UI at /docs

JSON Export

OpenAPI JSON spec

YAML Export

OpenAPI YAML spec

Available Methods

app.getOpenAPISpec()

Returns the OpenAPI specification as a JavaScript object

app.getDocsJSON()

Returns the OpenAPI specification as a JSON string

app.getDocsYAML()

Returns the OpenAPI specification as a YAML string

Installation

OpenAPI documentation requires the swagger-ui-dist package:

Install Dependencies

bash

1npm install @morojs/moro zod swagger-ui-dist

The swagger-ui-dist dependency is optional and only needed if you want to enable interactive documentation.

Next Steps