Pipes
In OzeanJs, a Pipe is a class that acts as a "tube" through which data flows before being sent to your Route Handler (a method in your Controller). A Pipe has two primary responsibilities:
- Validation: Checks if the incoming data meets the specified conditions. If not, it throws an exception to stop the process.
- Transformation: Converts incoming data into the desired format, such as converting the string "123" to the number
123
.
Pipes run after middleware but before the Route Handler is called, which is the ideal position for validating parameter data.
Using Pipes
We use the @UsePipes()
decorator to "attach" the desired Pipe to the Route Handler that needs data validation.
ValidationPipe
: The Automatic Validation Pipe
OzeanJs comes with a built-in ValidationPipe
, a powerful pipe that works with the class-validator
and class-transformer
libraries to automatically validate and transform data from the request body according to a specified DTO (Data Transfer Object).
Usage Example: Input Validation
Here is a complete example of using ValidationPipe
to validate data for creating a new user.
1. Install Dependencies (for Users)
Users of the library will need to install these 2 additional libraries:
bun add class-validator class-transformer
2. Create a DTO (Data Transfer Object)
A DTO is a class that acts as a "blueprint," defining the shape and validation rules for your expected data.
// src/users/dto/create-user.dto.ts
import { IsString, IsEmail, MinLength } from 'class-validator';
export class CreateUserDto {
@IsString({ message: 'Username must be a string' })
@MinLength(3, { message: 'Username must be at least 3 characters long' })
username!: string;
@IsEmail({}, { message: 'Please provide a valid email address' })
email!: string;
}
3. Register and Use ValidationPipe
in a Controller
// src/users/users.controller.ts
import { Controller, Post, Body, UsePipes, ValidationPipe } from 'ocean';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
@Controller('/users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
@UsePipes(ValidationPipe) // <-- Apply the ValidationPipe to this route
createUser(@Body() userData: CreateUserDto) {
// <-- Specify the Body's Type as the DTO
// At this point, we can be sure that userData is a valid instance of CreateUserDto
// and has been validated.
return this.usersService.create(userData);
}
}
4. Register the Pipe in a Module
Finally, don't forget to add ValidationPipe
to the providers
array of the relevant Module so the DI Container recognizes it.
// src/users/users.module.ts
import { Module } from 'ocean';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { ValidationPipe } from 'ocean'; // Import from Library
@Module({
controllers: [UsersController],
providers: [
UsersService,
ValidationPipe, // <-- Add here
],
})
export class UsersModule {}
Once this is done:
- If the client sends data that matches the DTO: The request will proceed to the
createUser
method as normal. - If the client sends incorrect data: The
ValidationPipe
will automatically throw aBadRequestException
, and the framework will respond with an HTTP Status 400 Bad Request along with the error details.