install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/nestjs-pipes-pattern" ~/.claude/skills/intense-visions-harness-engineering-nestjs-pipes-pattern-2e307f && rm -rf "$T"
manifest:
agents/skills/codex/nestjs-pipes-pattern/SKILL.mdsource content
NestJS Pipes Pattern
Validate and transform request data with PipeTransform, ValidationPipe, and custom pipes
When to Use
- You need to validate incoming request bodies against a DTO class
- You need to transform a string route parameter to a number, UUID, boolean, or enum
- You want validation to run automatically on all routes without per-handler boilerplate
- You are building a custom transformation (e.g., trim strings, normalize phone numbers)
Instructions
- Enable ValidationPipe globally in
(recommended for most applications):main.ts
app.useGlobalPipes( new ValidationPipe({ whitelist: true, // strip properties not in DTO forbidNonWhitelisted: true, // throw on extra properties transform: true, // auto-transform payload to DTO class instance transformOptions: { enableImplicitConversion: true }, }) );
- Use built-in transformation pipes as inline pipe arguments:
@Get(':id') findOne(@Param('id', ParseUUIDPipe) id: string) { ... } @Get(':page') list(@Query('page', ParseIntPipe) page: number) { ... } @Param('status', new ParseEnumPipe(UserStatus)) status: UserStatus
- Define DTO classes with class-validator decorators:
import { IsEmail, IsString, MinLength, IsOptional } from 'class-validator'; export class CreateUserDto { @IsEmail() email: string; @IsString() @MinLength(8) password: string; @IsOptional() @IsString() displayName?: string; }
- Custom pipe — implement
:PipeTransform<T, R>
@Injectable() export class TrimPipe implements PipeTransform<string, string> { transform(value: string): string { if (typeof value !== 'string') return value; return value.trim(); } }
-
Apply custom pipes at the parameter level:
.@Body('name', TrimPipe) name: string -
For pipes that may fail (e.g., parsing), throw
rather than returning null.BadRequestException
Details
Pipes serve two roles: validation (throw if invalid) and transformation (convert to the expected type). Both happen before the handler executes.
behavior: whitelist: true
ValidationPipe strips any property on the incoming JSON that has no corresponding decorator in the DTO. This prevents mass-assignment attacks where clients send unexpected fields (e.g., isAdmin: true). forbidNonWhitelisted: true goes further and throws a 400 if any extra property is present.
: Without this, transform: true
@Body() dto: CreateUserDto gives you a plain object, not a CreateUserDto instance. With it, NestJS runs class-transformer's plainToInstance automatically so you get a proper class instance and @Type() decorators work correctly.
Class-validator integration: All
class-validator decorators (@IsEmail(), @IsUUID(), @IsEnum(), @Min(), @Max(), etc.) work with ValidationPipe. Nested DTOs require @ValidateNested() combined with @Type(() => NestedDto).
Scope: Pipes can be applied at four levels (most specific wins):
- Global —
app.useGlobalPipes() - Controller —
@UsePipes() - Method —
@UsePipes() - Parameter — inline in
@Param('id', ParseUUIDPipe)
Async pipes:
transform() can return Promise<R>. This enables async validation (e.g., checking a database for uniqueness), though this is better done at the service layer.
Source
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.