@nest-toolbox/response-envelope
v1.8.1
Published
Standard API response envelope with interceptor, exception filter, and helpers for NestJS
Maintainers
Readme
@nest-toolbox/response-envelope
Standard API response envelope with interceptor, exception filter, and helpers for NestJS.
Features
- 🚀 Zero-config — import the module and every route gets a consistent envelope
- 🎯 Decorator-first —
@SkipEnvelope()and@ApiMessage()for per-route control - 🛡️ Consistent error formatting — class-validator errors auto-parsed into structured field errors
- 🔄 Idempotent — already-wrapped responses pass through untouched
- ⚙️ Configurable —
forRoot()/forRootAsync()for custom defaults - 📦 Manual helpers —
success(),error(),paginated()for WebSockets, queues, etc.
Installation
npm install @nest-toolbox/response-envelopeQuick Start
// app.module.ts
import { Module } from '@nestjs/common';
import { ResponseEnvelopeModule } from '@nest-toolbox/response-envelope';
@Module({
imports: [ResponseEnvelopeModule.forRoot()],
})
export class AppModule {}That's it! Every route now returns a consistent envelope. No interceptors to register, no filters to bind.
Response Format
Success
{
"success": true,
"data": { "id": 1, "name": "Alice" },
"message": "OK",
"meta": {
"timestamp": "2025-02-05T07:32:00.000Z",
"path": "/api/users/1",
"statusCode": 200
}
}Paginated Success
{
"success": true,
"data": [{ "id": 1 }, { "id": 2 }],
"message": "OK",
"meta": {
"timestamp": "2025-02-05T07:32:00.000Z",
"path": "/api/users",
"statusCode": 200,
"pagination": {
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5
}
}
}Error
{
"success": false,
"data": null,
"message": "Validation failed",
"errors": [
{ "field": "email", "message": "must be a valid email" },
{ "field": "name", "message": "should not be empty" }
],
"meta": {
"timestamp": "2025-02-05T07:32:00.000Z",
"path": "/api/users",
"statusCode": 400
}
}API Reference
ResponseEnvelopeModule.forRoot(options?)
Register the module globally with static options.
ResponseEnvelopeModule.forRoot({
defaultMessage: 'Success',
includePath: true,
includeTimestamp: true,
});| Option | Type | Default | Description |
|--------|------|---------|-------------|
| defaultMessage | string | 'OK' | Default success message when @ApiMessage() is not used |
| includePath | boolean | true | Include the request path in response meta |
| includeTimestamp | boolean | true | Include the ISO timestamp in response meta |
ResponseEnvelopeModule.forRootAsync(options)
Register the module with async factory injection.
ResponseEnvelopeModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
defaultMessage: config.get('API_DEFAULT_MESSAGE', 'OK'),
includePath: config.get('API_INCLUDE_PATH') !== 'false',
}),
inject: [ConfigService],
});@SkipEnvelope()
Skip the envelope for a specific route handler. The raw return value is sent as-is.
import { SkipEnvelope } from '@nest-toolbox/response-envelope';
@Controller()
export class AppController {
@Get('health')
@SkipEnvelope()
health() {
return { status: 'ok' }; // sent as-is, no envelope
}
}@ApiMessage(message)
Set a custom success message for a route handler.
import { ApiMessage } from '@nest-toolbox/response-envelope';
@Controller('users')
export class UsersController {
@Post()
@ApiMessage('User created successfully')
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
// → { success: true, data: { ... }, message: "User created successfully", meta: { ... } }
}success(data, options?)
Manually create a success envelope. Useful outside the HTTP interceptor (WebSocket gateways, message queues, etc.).
import { success } from '@nest-toolbox/response-envelope';
const response = success(user, {
message: 'User found',
path: '/api/users/1',
statusCode: 200,
});Options: message?: string, path?: string, statusCode?: number, pagination?: PaginationMeta
error(message, options?)
Manually create an error envelope.
import { error } from '@nest-toolbox/response-envelope';
const response = error('Validation failed', {
statusCode: 400,
errors: [{ field: 'email', message: 'must be a valid email' }],
path: '/api/users',
});Options: errors?: FieldError[], path?: string, statusCode?: number
paginated(data, pagination, options?)
Create a paginated success envelope with pagination metadata.
import { paginated } from '@nest-toolbox/response-envelope';
const response = paginated(users, { page: 1, limit: 20, total: 100 }, {
message: 'Users retrieved',
path: '/api/users',
});
// → meta.pagination = { page: 1, limit: 20, total: 100, totalPages: 5 }Pagination: page: number, limit: number, total: number
Options: message?: string, path?: string, statusCode?: number
Types
All types are exported from the package. See src/types.ts for full definitions.
| Type | Description |
|------|-------------|
| ApiResponse<T> | Standard success response envelope |
| ApiErrorResponse | Standard error response envelope |
| ResponseMeta | Metadata attached to every response (timestamp, path, statusCode) |
| PaginationMeta | Pagination info (page, limit, total, totalPages) |
| FieldError | Structured field-level error ({ field, message }) |
| ResponseEnvelopeOptions | Static configuration options for forRoot() |
| ResponseEnvelopeAsyncOptions | Async configuration options for forRootAsync() |
Integration with Other Toolbox Packages
@nest-toolbox/typeorm-paginate
The paginated() helper pairs naturally with @nest-toolbox/typeorm-paginate:
import { paginate } from '@nest-toolbox/typeorm-paginate';
import { paginated } from '@nest-toolbox/response-envelope';
@Get()
async findAll(@Query() query: PaginationDto) {
const result = await paginate(this.userRepository, {
page: query.page,
limit: query.limit,
});
return paginated(result.items, {
page: result.meta.currentPage,
limit: result.meta.itemsPerPage,
total: result.meta.totalItems,
});
}License
MIT © Bogdan Lupu
