Skip to main content

Swagger / OpenAPI

Muzu provides built-in Swagger/OpenAPI 3.0 documentation support with zero external dependencies. Generate interactive API documentation automatically from your decorators.

Quick Start

Enable Swagger by passing configuration to MuzuServer:

import { MuzuServer } from 'muzu';

const app = new MuzuServer({
swagger: {
enabled: true,
path: '/swagger',
info: {
title: 'My API',
version: '1.0.0',
description: 'API documentation',
contact: {
name: 'API Support',
email: 'support@example.com'
}
}
}
});

app.listen(3000);

Access your documentation:

Configuration Options

const app = new MuzuServer({
swagger: {
enabled: true, // Enable/disable Swagger
path: '/swagger', // Swagger UI path (default: /swagger)
debug: true, // Enable debug logs (default: false)

info: {
title: 'My API', // API title
version: '1.0.0', // API version
description: 'API docs', // API description
contact: {
name: 'Support',
email: 'support@example.com',
url: 'https://example.com/support'
},
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT'
}
},

servers: [ // Optional server definitions
{
url: 'http://localhost:3000',
description: 'Development server'
},
{
url: 'https://api.example.com',
description: 'Production server'
}
]
}
});

Documenting Controllers

Use @ApiTags to tag controllers:

import { Controller, Get, ApiTags } from 'muzu';

// Simple string tags
@Controller('/users')
@ApiTags('Users')
class UserController {
@Get()
getUsers() {
return { users: [] };
}
}

// Tags with descriptions
@Controller('/products')
@ApiTags({ name: 'Products', description: 'Product management endpoints' })
class ProductController {
@Get()
getProducts() {
return { products: [] };
}
}

Documenting Operations

Use @ApiOperation to document route details:

import { Get, Post, ApiOperation } from 'muzu';

@Controller('/users')
class UserController {
@Get()
@ApiOperation({
summary: 'Get all users',
description: 'Returns a list of all users in the system',
operationId: 'getAllUsers'
})
getUsers() {
return { users: [] };
}

@Post()
@ApiOperation({
summary: 'Create a new user',
description: 'Creates a new user with the provided information'
})
createUser(req: Request) {
return { created: true };
}
}

Documenting Responses

Use @ApiResponse to document responses:

import { Get, ApiResponse } from 'muzu';

class UserResponseDto {
@IsString()
id: string;

@IsString()
username: string;

@IsEmail()
email: string;
}

@Controller('/users')
class UserController {
@Get()
@ApiResponse({
status: 200,
description: 'Successful response',
type: UserResponseDto,
isArray: true
})
@ApiResponse({
status: 500,
description: 'Internal server error'
})
getUsers() {
return { users: [] };
}

@Get(':id')
@ApiResponse({
status: 200,
description: 'User found',
type: UserResponseDto
})
@ApiResponse({
status: 404,
description: 'User not found'
})
getUser(req: Request) {
return { user: {} };
}
}

Documenting Parameters

Use @ApiParameter to document path/query/header parameters:

import { Get, ApiParameter } from 'muzu';

@Controller('/users')
class UserController {
@Get(':id')
@ApiParameter({
name: 'id',
in: 'path',
description: 'User ID',
required: true,
type: 'string',
example: '123'
})
getUser(req: Request) {
return { userId: req.params.id };
}

@Get()
@ApiParameter({
name: 'page',
in: 'query',
description: 'Page number',
required: false,
type: 'integer',
example: 1
})
@ApiParameter({
name: 'limit',
in: 'query',
description: 'Items per page',
required: false,
type: 'integer',
example: 10
})
@ApiParameter({
name: 'Authorization',
in: 'header',
description: 'Bearer token',
required: true,
type: 'string',
example: 'Bearer abc123'
})
getUsers(req: Request) {
return { users: [] };
}
}

Documenting Request Body

Use @ApiBody to document request bodies:

import { Post, ApiBody, ValidateBody } from 'muzu';

class CreateUserDto {
@IsString()
@MinLength(3)
username: string;

@IsEmail()
email: string;

@IsNumber()
@Min(18)
age: number;
}

@Controller('/users')
class UserController {
@Post()
@ApiBody({
description: 'User data',
required: true,
type: CreateUserDto
})
@ValidateBody(CreateUserDto)
createUser(req: Request) {
return { created: true };
}
}

Automatic Schema Generation

Muzu automatically generates JSON schemas from your DTOs:

class CreateUserDto {
@IsString()
@MinLength(3)
@MaxLength(20)
username: string; // → { type: 'string', minLength: 3, maxLength: 20 }

@IsEmail()
email: string; // → { type: 'string', format: 'email' }

@IsNumber()
@Min(18)
@Max(100)
age: number; // → { type: 'number', minimum: 18, maximum: 100 }

@IsEnum(UserRole)
role: UserRole; // → { enum: ['admin', 'user', 'guest'] }
}

The schema appears in Swagger UI automatically when you use @ApiBody or @ApiResponse with type: CreateUserDto.

Complete Example

Here's a fully documented controller:

import {
Controller,
Get,
Post,
Put,
Delete,
ApiTags,
ApiOperation,
ApiResponse,
ApiParameter,
ApiBody,
ValidateBody,
IsString,
IsEmail,
IsNumber,
Min,
Max,
MinLength
} from 'muzu';

// DTOs
class CreateUserDto {
@IsString()
@MinLength(3)
username: string;

@IsEmail()
email: string;

@IsNumber()
@Min(18)
@Max(100)
age: number;
}

class UserResponseDto {
@IsString()
id: string;

@IsString()
username: string;

@IsEmail()
email: string;

@IsNumber()
age: number;
}

// Controller
@Controller('/api/users')
@ApiTags({ name: 'Users', description: 'User management endpoints' })
export class UserController {
@Get()
@ApiOperation({
summary: 'Get all users',
description: 'Returns a list of all users in the system'
})
@ApiResponse({
status: 200,
description: 'Successful response',
type: UserResponseDto,
isArray: true
})
getUsers() {
return {
users: [
{ id: '1', username: 'alice', email: 'alice@example.com', age: 25 },
{ id: '2', username: 'bob', email: 'bob@example.com', age: 30 }
]
};
}

@Get(':id')
@ApiOperation({
summary: 'Get user by ID',
description: 'Returns a single user by their ID'
})
@ApiParameter({
name: 'id',
in: 'path',
description: 'User ID',
required: true,
type: 'string'
})
@ApiResponse({
status: 200,
description: 'User found',
type: UserResponseDto
})
@ApiResponse({
status: 404,
description: 'User not found'
})
getUser(req: Request) {
const { id } = req.params;
return {
id,
username: 'alice',
email: 'alice@example.com',
age: 25
};
}

@Post()
@ApiOperation({
summary: 'Create a new user',
description: 'Creates a new user with the provided information'
})
@ApiBody({
description: 'User data',
required: true,
type: CreateUserDto
})
@ApiResponse({
status: 201,
description: 'User created successfully',
type: UserResponseDto
})
@ApiResponse({
status: 400,
description: 'Invalid input'
})
@ValidateBody(CreateUserDto)
createUser(req: Request, res: Response) {
res.statusCode = 201;
return {
id: '123',
...req.body
};
}
}

Automatic Tag Collection

Tags are automatically collected from @ApiTags decorators:

// ✅ Tags are auto-collected
@Controller('/users')
@ApiTags({ name: 'Users', description: 'User management' })
class UserController { }

@Controller('/products')
@ApiTags({ name: 'Products', description: 'Product management' })
class ProductController { }

// ❌ No need to define tags in config
const app = new MuzuServer({
swagger: {
// tags: [...] // Not needed! Muzu collects them automatically
info: { ... }
}
});

You can use either format:

  • String: @ApiTags('Users', 'Products')
  • Object: @ApiTags({ name: 'Users', description: '...' })
  • Mixed: @ApiTags('Auth', { name: 'Users', description: '...' })

Debug Mode

Enable debug mode to see Swagger generation warnings:

const app = new MuzuServer({
swagger: {
enabled: true,
debug: true, // Show warnings in console
info: { ... }
}
});

Debug mode shows warnings for:

  • Failed spec generation
  • Failed operation building
  • Failed schema generation

Multiple Responses

Document multiple response codes:

@Get(':id')
@ApiResponse({
status: 200,
description: 'User found',
type: UserResponseDto
})
@ApiResponse({
status: 404,
description: 'User not found'
})
@ApiResponse({
status: 401,
description: 'Unauthorized'
})
@ApiResponse({
status: 500,
description: 'Internal server error'
})
getUser(req: Request) {
// ...
}

Array Responses

Document array responses:

@Get()
@ApiResponse({
status: 200,
description: 'List of users',
type: UserResponseDto,
isArray: true // Important!
})
getUsers() {
return { users: [] };
}

Nested DTOs

Swagger automatically handles nested DTOs:

class AddressDto {
@IsString()
street: string;

@IsString()
city: string;
}

class UserDto {
@IsString()
name: string;

@ValidateNested()
address: AddressDto; // Nested DTO
}

@Post()
@ApiBody({
type: UserDto // Automatically includes AddressDto schema
})
@ValidateBody(UserDto)
createUser(req: Request) {
return { created: true };
}

Best Practices

Document All Public Endpoints

// ✅ Good - Fully documented
@Get(':id')
@ApiOperation({ summary: 'Get user by ID' })
@ApiParameter({ name: 'id', in: 'path', type: 'string' })
@ApiResponse({ status: 200, type: UserDto })
@ApiResponse({ status: 404, description: 'Not found' })
getUser() { }

// ❌ Bad - No documentation
@Get(':id')
getUser() { }

Use Descriptive Messages

// ✅ Good - Clear descriptions
@ApiOperation({
summary: 'Get user by ID',
description: 'Retrieves a single user by their unique identifier'
})

// ❌ Bad - Vague descriptions
@ApiOperation({
summary: 'Get user',
description: 'Gets user'
})
// ✅ Good - Grouped with tags
@Controller('/users')
@ApiTags({ name: 'Users', description: 'User management' })
class UserController { }

@Controller('/posts')
@ApiTags({ name: 'Posts', description: 'Post management' })
class PostController { }

// ❌ Bad - No grouping
@Controller('/users')
class UserController { } // No tags

Document Error Responses

// ✅ Good - Error responses documented
@Get(':id')
@ApiResponse({ status: 200, type: UserDto })
@ApiResponse({ status: 404, description: 'User not found' })
@ApiResponse({ status: 500, description: 'Internal server error' })
getUser() { }

// ❌ Bad - Only success response
@Get(':id')
@ApiResponse({ status: 200, type: UserDto })
getUser() { }

Swagger UI Features

The generated Swagger UI includes:

  • Try it out - Test endpoints directly from the browser
  • Schema viewer - View request/response schemas
  • Example values - See example payloads
  • Authentication - Test with auth tokens
  • Download - Export OpenAPI spec as JSON/YAML

Next Steps