@royzhang107/nest-casing
v0.1.8
Published
NestJS module for automatic request/response casing transformation (snake_case ↔ camelCase)
Downloads
665
Maintainers
Readme
@royzhang107/nest-casing
A NestJS module for automatic request/response casing transformation between snake_case and camelCase.
Write your DTOs in camelCase while your API communicates in snake_case — automatically.
Features
- 🔄 Bidirectional transformation — Incoming
snake_case→camelCase, outgoingcamelCase→snake_case - 🌐 Global module — Apply once, works everywhere
- 🎯 Flexible — Use globally or per-route with interceptors/pipes
- 📦 Pure TypeScript — Zero external dependencies for casing logic
- 🔧 Configurable — Optional ValidationPipe integration
- ⚡ Dual ESM/CJS — Works in any module system
Installation
npm install @royzhang107/nest-casingQuick Start
Global Module (Recommended)
Import CasingModule in your root module:
import { Module } from '@nestjs/common';
import { CasingModule } from '@royzhang107/nest-casing';
@Module({
imports: [
CasingModule.forRoot(),
],
})
export class AppModule {}That's it! Your API now:
- Accepts
snake_caserequest bodies and transforms them tocamelCase - Returns responses with
camelCasekeys transformed tosnake_case
Configuration Options
CasingModule.forRoot({
// Default: 'snake-to-camel'
// - 'snake-to-camel': Input snake_case → camelCase, Output camelCase → snake_case
// - 'camel-to-snake': Input camelCase → snake_case, Output snake_case → camelCase
direction: 'snake-to-camel',
// Enable built-in ValidationPipe
enableValidation: true,
validationOptions: {
transform: true,
whitelist: true,
forbidNonWhitelisted: false,
},
})Async Configuration
Use forRootAsync when options depend on other providers:
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { CasingModule } from '@royzhang107/nest-casing';
@Module({
imports: [
ConfigModule.forRoot(),
CasingModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
direction: config.get('CASING_DIRECTION') || 'snake-to-camel',
enableValidation: true,
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}Per-Route Usage
Use interceptors and pipes individually when you need fine-grained control:
import { Controller, Post, Body, UseInterceptors, UsePipes } from '@nestjs/common';
import {
CamelToSnakeInterceptor,
SnakeToCamelPipe,
} from '@royzhang107/nest-casing';
@Controller('users')
export class UsersController {
@Post()
@UseInterceptors(CamelToSnakeInterceptor)
@UsePipes(SnakeToCamelPipe)
create(@Body() createUserDto: CreateUserDto) {
// createUserDto has camelCase keys
return this.usersService.create(createUserDto);
// Response will have snake_case keys
}
}Utility Functions
The casing utilities are also exported for direct use:
import {
toCamelCase,
toSnakeCase,
keysToCamel,
keysToSnake,
} from '@royzhang107/nest-casing';
// String transformation
toCamelCase('user_name'); // 'userName'
toSnakeCase('userName'); // 'user_name'
// Deep object key transformation
keysToCamel({ user_name: 'John', user_age: 30 });
// { userName: 'John', userAge: 30 }
keysToSnake({ userName: 'John', userAge: 30 });
// { user_name: 'John', user_age: 30 }Available Utilities
| Function | Description |
|----------|-------------|
| toCamelCase(str) | Convert string to camelCase |
| toSnakeCase(str) | Convert string to snake_case |
| toPascalCase(str) | Convert string to PascalCase |
| toKebabCase(str) | Convert string to kebab-case |
| keysToCamel(obj) | Deep transform object keys to camelCase |
| keysToSnake(obj) | Deep transform object keys to snake_case |
| keysToPascal(obj) | Deep transform object keys to PascalCase |
| keysToKebab(obj) | Deep transform object keys to kebab-case |
| transformKeys(obj, fn) | Deep transform object keys with custom function |
Usage in Nx Monorepo
Importing the Library
In your Nx workspace, import from the library path:
// In apps/your-app/src/app/app.module.ts
import { CasingModule } from '@royzhang107/nest-casing';Building the Library
# Build the library
npx nx build @royzhang/nest-casing
# Build with production config
npx nx build @royzhang/nest-casing --configuration=production
# Run tests
npx nx test @royzhang/nest-casing
# Lint
npx nx lint @royzhang/nest-casingPath Mapping
The workspace already has the path mapping in tsconfig.base.json:
{
"compilerOptions": {
"paths": {
"@royzhang107/nest-casing": ["libs/nestjs-casing/src/index.ts"]
}
}
}API Reference
CasingModule
| Method | Description |
|--------|-------------|
| forRoot(options?) | Register module with static configuration |
| forRootAsync(options) | Register module with async configuration |
Interceptors
| Class | Description |
|-------|-------------|
| CamelToSnakeInterceptor | Transform response keys from camelCase to snake_case |
| SnakeToCamelInterceptor | Transform response keys from snake_case to camelCase |
Pipes
| Class | Description |
|-------|-------------|
| SnakeToCamelPipe | Transform request body keys from snake_case to camelCase |
| CamelToSnakePipe | Transform request body keys from camelCase to snake_case |
Example Flow
Request Body (from client):
{
"user_name": "john_doe",
"email_address": "[email protected]"
}
↓
SnakeToCamelPipe transforms to:
{
"userName": "john_doe",
"emailAddress": "[email protected]"
}
↓
Your controller/service works with camelCase
↓
CamelToSnakeInterceptor transforms response:
{
"user_name": "john_doe",
"email_address": "[email protected]",
"created_at": "2024-01-01T00:00:00Z"
}License
MIT
