Swagger Package
The @hazeljs/swagger package provides automatic OpenAPI/Swagger documentation generation for your HazelJS applications. It scans your controllers and generates comprehensive API documentation with minimal configuration.
Purpose
API documentation is essential for developer adoption, but maintaining it manually is time-consuming and error-prone. Keeping documentation in sync with code changes requires constant updates. The @hazeljs/swagger package solves this by providing:
- Automatic Generation: Scans your controllers and generates OpenAPI specs automatically
- Decorator-Based: Use decorators to document endpoints without writing separate docs
- Type Safety: Leverages TypeScript types for accurate documentation
- Interactive UI: Built-in Swagger UI for testing and exploring your API
- Standards Compliant: Generates OpenAPI 3.0 compliant specifications
Architecture
The package uses reflection and decorators to extract API information:
Key Components
- SwaggerService: Generates OpenAPI specifications from controllers
- SwaggerController: Serves Swagger UI and API specs
- Decorators:
@Swagger,@ApiOperationfor documenting endpoints - Metadata Extraction: Uses reflection to extract route information
Advantages
1. Always Up-to-Date
Documentation is generated from your code, so it's always synchronized with your API.
2. Developer Experience
Use decorators to document endpoints—no need to maintain separate documentation files.
3. Interactive Testing
Swagger UI allows developers to test your API directly from the documentation.
4. Standards Compliant
Generates OpenAPI 3.0 specs that work with all standard tools and clients.
5. Type Safety
Leverages TypeScript types to ensure accurate request/response documentation.
6. Easy Integration
Works seamlessly with HazelJS controllers—no additional setup required.
Installation
npm install @hazeljs/swagger
Quick Start
Basic Setup
import { HazelModule } from '@hazeljs/core';
import { SwaggerModule } from '@hazeljs/swagger';
import { AppModule } from './app.module';
@HazelModule({
imports: [
SwaggerModule,
],
})
export class AppModule {}
// Set root module for Swagger
SwaggerModule.setRootModule(AppModule);
Access Swagger UI
Once configured, access Swagger UI at:
http://localhost:3000/swagger
Swagger Decorator
Decorators and Annotations
The Swagger package provides decorators for automatically generating OpenAPI documentation. These decorators use metadata to extract API information and generate comprehensive documentation.
Understanding Swagger Decorators
Swagger decorators work together to build OpenAPI specifications:
- Class Decorators: Configure API-level information
- Method Decorators: Document individual endpoints
- Metadata Extraction: Framework reads decorator metadata to generate specs
@Swagger Decorator
The @Swagger decorator is a class decorator that configures OpenAPI documentation for a controller.
Purpose: Defines API-level metadata like title, description, version, and tags. This information appears at the top of your Swagger documentation.
How it works:
- Stores API metadata in class metadata
SwaggerServicereads this when generating the OpenAPI spec- Information appears in the Swagger UI header and info section
Configuration Options:
interface SwaggerOptions {
title?: string; // API title
description?: string; // API description
version?: string; // API version (e.g., '1.0.0')
contact?: { // Contact information
name?: string;
email?: string;
url?: string;
};
license?: { // License information
name: string;
url?: string;
};
servers?: Array<{ // Server URLs
url: string;
description?: string;
}>;
tags?: Array<{ // API tags for grouping
name: string;
description?: string;
}>;
}
Use the @Swagger decorator to document your controllers:
import { Controller, Get, Post, Body, Param } from '@hazeljs/core';
import { Swagger, ApiOperation } from '@hazeljs/swagger';
// @Swagger is a class decorator that configures API documentation
@Swagger({
title: 'My API', // Appears in Swagger UI header
description: 'API documentation for my application',
// Detailed description of what your API does
// Supports Markdown for formatting
version: '1.0.0', // API version
// Used for versioning and change tracking
tags: [
{
name: 'Users',
description: 'User management endpoints'
},
{
name: 'Products',
description: 'Product management endpoints'
},
],
// Tags group related endpoints in Swagger UI
// Makes documentation easier to navigate
})
@Controller('users')
export class UsersController {
// All endpoints in this controller will be documented
// with the above API-level information
@ApiOperation({
summary: 'Get all users', // Short description
// Appears in the endpoint list in Swagger UI
// Keep it concise (one line)
description: 'Retrieve a list of all users with optional filtering',
// Detailed description
// Supports Markdown for formatting
// Explain what the endpoint does, any side effects, etc.
tags: ['Users'], // Group this endpoint
// Appears under "Users" tag in Swagger UI
// Can override controller-level tags
responses: {
'200': {
description: 'List of users retrieved successfully',
content: {
'application/json': {
schema: {
type: 'array',
items: { $ref: '#/components/schemas/User' },
// Reference to a schema definition
// Or inline schema definition
},
},
},
},
},
// Documents possible responses
// Swagger UI shows example responses
// Helps API consumers understand what to expect
})
@Get()
async findAll() {
return [];
}
// @ApiOperation documents individual endpoints
@ApiOperation({
summary: 'Get user by ID', // Short, one-line summary
description: 'Retrieve a specific user by their ID. Returns 404 if user not found.',
// Detailed description with important notes
tags: ['Users'], // Group under Users tag
parameters: [
{
name: 'id',
in: 'path', // Path parameter (from URL)
required: true, // Must be provided
schema: {
type: 'integer',
minimum: 1, // Validation constraints
},
description: 'Unique user identifier',
example: 123, // Example value for Swagger UI
},
],
// Documents path, query, and header parameters
// Swagger UI generates input fields based on this
responses: {
'200': {
description: 'User found and returned successfully',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/User' },
// Reference to shared schema
// Or define inline: schema: { type: 'object', properties: {...} }
},
},
},
'404': {
description: 'User with the specified ID was not found',
// Document all possible error responses
// Helps API consumers handle errors properly
},
},
})
@Get(':id')
async findOne(@Param('id') id: string) {
// The decorator metadata is used to generate OpenAPI spec
// Framework extracts route info and combines with decorator metadata
return { id: parseInt(id) };
}
@ApiOperation({
summary: 'Create a new user',
description: 'Creates a new user account with the provided information. Email must be unique.',
tags: ['Users'],
requestBody: {
required: true,
description: 'User creation data',
content: {
'application/json': {
// Inline schema definition with examples
schema: {
type: 'object',
properties: {
name: {
type: 'string',
example: 'John Doe',
minLength: 1,
maxLength: 100,
},
email: {
type: 'string',
format: 'email',
example: 'john@example.com',
},
},
required: ['name', 'email'],
},
// Or use schema reference:
// schema: { $ref: '#/components/schemas/CreateUserDto' }
},
},
},
responses: {
'201': {
description: 'User created successfully',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/User' },
},
},
},
'400': {
description: 'Invalid input data. Check validation errors.',
},
'409': {
description: 'User with this email already exists',
},
},
})
@Post()
async create(@Body() createUserDto: CreateUserDto) {
return createUserDto;
}
}
@ApiOperation Decorator Explained
The @ApiOperation decorator is a method decorator that provides comprehensive documentation for API endpoints.
How it works:
- Metadata Storage: Stores operation details in method metadata
- Spec Generation:
SwaggerServicereads this metadata when generating OpenAPI spec - UI Rendering: Swagger UI uses this to render interactive documentation
- Route Integration: Combines with route metadata from
@Get,@Post, etc.
Key Configuration Areas:
1. Summary and Description:
summary: Short, one-line description (appears in endpoint list)description: Detailed explanation (supports Markdown)
2. Parameters: Document path, query, and header parameters:
parameters: [
{
name: 'id',
in: 'path', // 'path', 'query', or 'header'
required: true,
schema: {
type: 'integer',
minimum: 1,
},
description: 'User identifier',
example: 123,
},
]
3. Request Body: Define request body structure:
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
properties: { /* ... */ },
required: [/* ... */],
},
},
},
}
4. Responses: Document all possible responses:
responses: {
'200': { /* success response */ },
'400': { /* validation error */ },
'404': { /* not found */ },
'500': { /* server error */ },
}
Best Practices:
- Be comprehensive: Document all parameters, request body, and responses
- Use examples: Provide example values for better understanding
- Include validation: Add constraints (min, max, pattern) to schemas
- Document errors: Include all possible error responses
- Use schema references: Reuse common schemas for consistency
- Keep it updated: Update documentation when endpoints change
Swagger Service
Use the SwaggerService to programmatically generate OpenAPI specs:
import { Injectable } from '@hazeljs/core';
import { SwaggerService } from '@hazeljs/swagger';
@Injectable()
export class ApiService {
constructor(private readonly swaggerService: SwaggerService) {}
getOpenApiSpec() {
const controllers = [UsersController, ProductsController];
return this.swaggerService.generateSpec(controllers);
}
}
Swagger Controller
The SwaggerController provides endpoints for accessing Swagger documentation:
GET /swagger- Swagger UIGET /swagger/json- OpenAPI JSON specificationGET /swagger/yaml- OpenAPI YAML specification
Complete Example
import { HazelModule } from '@hazeljs/core';
import { SwaggerModule, Swagger, ApiOperation } from '@hazeljs/swagger';
import { Controller, Get, Post, Body, Param } from '@hazeljs/core';
// Define DTOs
interface User {
id: number;
name: string;
email: string;
}
interface CreateUserDto {
name: string;
email: string;
}
// Controller with Swagger documentation
@Swagger({
title: 'User API',
description: 'User management API',
version: '1.0.0',
tags: [{ name: 'Users', description: 'User operations' }],
})
@Controller('users')
export class UsersController {
@ApiOperation({
summary: 'List all users',
tags: ['Users'],
responses: {
'200': {
description: 'Successful response',
},
},
})
@Get()
async findAll(): Promise<User[]> {
return [];
}
@ApiOperation({
summary: 'Get user by ID',
tags: ['Users'],
parameters: [
{
name: 'id',
in: 'path',
required: true,
schema: { type: 'integer' },
},
],
responses: {
'200': { description: 'User found' },
'404': { description: 'User not found' },
},
})
@Get(':id')
async findOne(@Param('id') id: string): Promise<User> {
return { id: parseInt(id), name: 'John', email: 'john@example.com' };
}
@ApiOperation({
summary: 'Create user',
tags: ['Users'],
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
properties: {
name: { type: 'string' },
email: { type: 'string', format: 'email' },
},
required: ['name', 'email'],
},
},
},
},
responses: {
'201': { description: 'User created' },
'400': { description: 'Invalid input' },
},
})
@Post()
async create(@Body() createUserDto: CreateUserDto): Promise<User> {
return {
id: 1,
...createUserDto,
};
}
}
// Module setup
@HazelModule({
imports: [SwaggerModule],
controllers: [UsersController],
})
export class AppModule {}
SwaggerModule.setRootModule(AppModule);
Customization
Custom Swagger UI Path
Configure a custom path for Swagger UI:
SwaggerModule.forRoot({
path: '/api-docs', // Custom path
title: 'My API',
version: '1.0.0',
});
Additional Configuration
@Swagger({
title: 'My API',
description: 'Comprehensive API documentation',
version: '1.0.0',
contact: {
name: 'API Support',
email: 'support@example.com',
},
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT',
},
servers: [
{ url: 'https://api.example.com', description: 'Production' },
{ url: 'https://staging-api.example.com', description: 'Staging' },
],
tags: [
{ name: 'Users', description: 'User management' },
{ name: 'Products', description: 'Product management' },
],
})
Best Practices
-
Document all endpoints: Use
@ApiOperationfor every route handler. -
Define schemas: Use schema references for request/response bodies.
-
Add descriptions: Provide clear descriptions for all operations.
-
Use tags: Organize endpoints with tags for better navigation.
-
Include examples: Add examples to help API consumers.
-
Version your API: Include version information in your Swagger configuration.
What's Next?
- Learn about Controllers for routing
- Explore Config for API configuration
- Check out Auth for securing your API