Skip to content

Pipe

Pipe chuyển đổi và xác thực dữ liệu đầu vào trước khi đến bộ xử lý route.

Pipe tích hợp

Orbit cung cấp một số pipe tích hợp:

ParseIntPipe

typescript
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
  // id chắc chắn là số
  return { id };
}

ParseBoolPipe

typescript
@Get()
findAll(@Query('active', ParseBoolPipe) active: boolean) {
  return { active };
}

ParseFloatPipe

typescript
@Get()
findByPrice(@Query('price', ParseFloatPipe) price: number) {
  return { price };
}

ParseArrayPipe

typescript
@Get()
findByIds(@Query('ids', ParseArrayPipe) ids: string[]) {
  return { ids };
}

DefaultValuePipe

typescript
@Get()
findAll(
  @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
  @Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number
) {
  return { page, limit };
}

TrimPipe

typescript
@Post()
create(@Body('name', TrimPipe) name: string) {
  // name đã được cắt khoảng trắng
  return { name };
}

Pipe xác thực với Zod

typescript
import { z } from 'zod';
import { ZodValidationPipe } from '@galaxy-stack/orbit-validation';

const CreateUserSchema = z.object({
  name: z.string().min(2).max(100),
  email: z.string().email(),
  age: z.number().min(18).optional(),
});

type CreateUserDto = z.infer<typeof CreateUserSchema>;

@Controller('users')
export class UserController {
  @Post()
  @UsePipes(new ZodValidationPipe(CreateUserSchema))
  create(@Body() dto: CreateUserDto) {
    return dto;
  }
}

Pipe tùy chỉnh

typescript
import { PipeTransform, Injectable, BadRequestException } from '@galaxy-stack/orbit-core';

@Injectable()
export class ParseUUIDPipe implements PipeTransform<string, string> {
  transform(value: string): string {
    const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
    
    if (!uuidRegex.test(value)) {
      throw new BadRequestException('Định dạng UUID không hợp lệ');
    }
    
    return value;
  }
}

// Sử dụng
@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) {
  return { id };
}

Pipe bất đồng bộ

typescript
@Injectable()
export class UserExistsPipe implements PipeTransform {
  constructor(private userService: UserService) {}

  async transform(value: string): Promise<User> {
    const user = await this.userService.findOne(value);
    
    if (!user) {
      throw new NotFoundException(`Người dùng ${value} không tồn tại`);
    }
    
    return user;
  }
}

// Sử dụng
@Get(':id')
findOne(@Param('id', UserExistsPipe) user: User) {
  return user;
}

Pipe toàn cục

typescript
const app = await BunFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());

Ngữ cảnh Pipe

Truy cập metadata trong pipe tùy chỉnh:

typescript
@Injectable()
export class ContextAwarePipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata): any {
    console.log('Loại:', metadata.type); // 'body', 'query', 'param'
    console.log('Dữ liệu:', metadata.data); // tên tham số
    console.log('Kiểu:', metadata.metatype); // kiểu mong đợi
    
    return value;
  }
}

Kết hợp Pipe

Pipe thực thi theo thứ tự:

typescript
@Get()
findAll(
  @Query('page', new DefaultValuePipe('1'), ParseIntPipe) page: number
) {
  // DefaultValuePipe đặt '1' nếu thiếu
  // ParseIntPipe chuyển đổi sang số
  return { page };
}

Released under the MIT License.