NestJS → Postman collection
The usual route from NestJS to Postman goes through @nestjs/swagger: install it, decorate the DTOs, boot the app, export the JSON, import it. routeman-cli reads your controllers and DTOs directly and skips all of that. You don't need decorators, a build or a running app.
$ npx routeman-cli
What routeman-cli reads from a NestJS app
- Routes: every
@Controllerin your modules, withsetGlobalPrefix(), URI versioning (enableVersioning,@Version) andRouterModulepaths applied. - Bodies: class-validator DTOs (
@IsEmail,@Length,@Min/@Max,@IsEnum,@IsOptional…),@ApiPropertyif you have it, andPartialType,PickTypeandOmitType. - Parameters:
@Query('page'),@Param('id', ParseIntPipe)andParseUUIDPipefor typed path variables. - Uploads:
FileInterceptor('file')becomes a form-data request with a file picker. - Auth:
@UseGuards(AuthGuard('jwt')), a globalAPP_GUARD, and the common@Public()decorator pattern for routes that skip it. - Names: the JSDoc comment on a handler method, or
@ApiOperation({ summary }).
Example
// src/main.ts
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('api');
app.enableVersioning({ type: VersioningType.URI, defaultVersion: '1' });
await app.listen(3000);
// src/app.module.ts
@Module({
controllers: [AuthController, ProductsController],
providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }],
})
export class AppModule {}
// src/products/product.dto.ts
export class CreateProductDto {
@IsString() @Length(3, 120) name: string;
@IsNumber() @Min(1) price: number;
@IsEnum(Category) category: Category;
@IsInt() @Min(0) @Max(10000) stock: number;
@IsOptional() @IsString() description?: string;
}
export class UpdateProductDto extends PartialType(CreateProductDto) {}
// src/auth/auth.controller.ts
@Controller('auth')
export class AuthController {
/** Exchange email and password for an access token */
@Public()
@Post('login')
login(@Body() dto: LoginDto) { ... }
/** The signed-in user */
@Get('me')
me(@Req() req) { ... }
}
// src/products/products.controller.ts
@Controller('products')
export class ProductsController {
@Public() @Get()
findAll(@Query('page') page?: number, @Query('q') q?: string) { ... }
@Public() @Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) { ... }
@Post()
create(@Body() dto: CreateProductDto) { ... }
@Patch(':id')
update(@Param('id', ParseIntPipe) id: number, @Body() dto: UpdateProductDto) { ... }
@Post(':id/image')
@UseInterceptors(FileInterceptor('file'))
upload(@Param('id', ParseIntPipe) id: number, @UploadedFile() file) { ... }
@Delete(':id')
remove(@Param('id', ParseIntPipe) id: number) { ... }
}
$ npx routeman-cli
✓ nest: 8 requests (3 POST, 3 GET, 1 PATCH, 1 DELETE)
✓ auth: bearer (login: POST /api/v1/auth/login)
✓ wrote postman/nest-shop-api.postman_collection.json
✓ wrote postman/nest-shop-api.local.postman_environment.json
done in 0.07s - import the files in Postman (File → Import)
$ npx routeman-cli routes
POST /api/v1/auth/login json: email, password
GET /api/v1/auth/me 🔒
GET /api/v1/products
POST /api/v1/products 🔒 json: name, price, category, stock, description
DELETE /api/v1/products/{id} 🔒
GET /api/v1/products/{id}
PATCH /api/v1/products/{id} 🔒 json: name, price, category, stock, description
POST /api/v1/products/{id}/image 🔒 form: file
8 routes, auth: bearer (login: POST /api/v1/auth/login)
This is real output from routeman-cli 0.1.0. Notice what it put together:
- Paths include both the global prefix and the default URI version:
/api/v1/…. - Auth: the global
APP_GUARDprotects everything, and the three@Public()routes are set to No Auth. The JSDoc comment names the login request Exchange email and password for an access token, and it stores the token it receives. - Create product gets
{"name": "John Doe", "price": 100, "category": "books", "stock": 1, "description": "Sample text"}. The name meets@Length(3, 120), the price meets@Min(1), and the category is a real enum value. - Update product is a PATCH with the same fields, all optional, from
PartialType. - List products has
pageandqquery parameters, switched off. ParseIntPipemakes{{productId}}an integer variable in the environment, andbase_urlishttp://localhost:3000fromapp.listen(3000).
Already using @nestjs/swagger?
routeman-cli reads @ApiProperty and @ApiOperation when they're present, so you lose nothing. You can also build from the spec your app serves: npx routeman-cli --openapi http://localhost:3000/docs-json. Building from the code means no running app and no forgotten decorators.
Full walkthrough: NestJS to Postman without @nestjs/swagger.