Xây dựng REST API với NestJS và Prisma (Phần 2)
Giới thiệu
Ở phần 1, mình đã thực hiện các bước khởi tạo nestjs project, cài đặt Prisma để quản lý database, tạo bảng User và data mẫu.
Ở phần 2 này, mình sẽ tới bước viết API CRUD cơ bản cho dự án nestjs nhé. 🤩
3. Triển khai API CRUD cho model User
Trong phần này, mình sẽ triển khai các hoạt động Create, Read, Update và Delete (CRUD) cho model User
mà chúng ta đã tạo thành công ở phần 1.
Tạo REST resources
Trước khi có thể triển khai API REST, bạn sẽ cần tạo REST resources cho model User
đã. Việc này có thể được thực hiện nhanh chóng bằng cách sử dụng Nest CLI. Chạy lệnh sau trong terminal của bạn:
npx nest generate resource
CLI sẽ hiển thị các câu hỏi sau.
$ npx nest generate resource
? What name would you like to use for this resource (plural, e.g., "users")?
// Điền users
? What transport layer do you use?
// Chọn option REST API
? Would you like to generate CRUD entry points? (Y/n)
// Y
CLI sẽ tự động tạo User
resources và các thành phần bên trong nó
Bây giờ bạn sẽ tìm thấy một thư mục src/users mới. Bên trong filesrc/users/users.controller.ts
, bạn sẽ thấy định nghĩa của các routes khác nhau (còn được gọi là route handlers) . Logic xử lý sẽ được viết trong file src/users/users.service.ts.
Thêm PrismaClient vào User module
Để truy cập PrismaClient bên trong module User, ta phải import PrismaModule như sau
import { PrismaModule } from './../prisma/prisma.module';
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
@Module({
controllers: [UsersController],
providers: [UsersService],
imports: [PrismaModule]
})
export class UsersModule {}
Bây giờ ta có thể đưa PrismaService vào trong UsersService và sử dụng nó để truy cập vào DB. Để thực hiện việc này, hãy thêm constructor ở User.service.ts như thế này:
// src/users/users.service.ts
@Injectable()
export class UsersService {
constructor(private prisma: PrismaService) {}
create(createUserDto: CreateUserDto) {
return 'This action adds a new user';
}
findAll() {
return `This action returns all users`;
}
findOne(id: number) {
return `This action returns a #${id} user`;
}
update(id: number, updateUserDto: UpdateUserDto) {
return `This action updates a #${id} user`;
}
remove(id: number) {
return `This action removes a #${id} user`;
}
}
Xong bước này thì chúng ta có thể bắt tay vào việc viết API rồi.
Define GET /users endpoint
Controller cho endpoint này là findAll. Endpoint này sẽ trả về tất cả các Users có trong cơ sở dữ liệu.
// src/users/users.controller.ts
@Get()
findAll() {
return this.usersService.findAll();
}
// src/users/users.service.ts
findAll() {
return this.prisma.user.findMany();
}
findMany() sẽ trả về tất cả các bản ghi users
Truy cập endpoint http://localhost:8000/users
và đây là kết quả:
Define GET /users/:id
Controller cho endpoint này là findOne. Endpoint này sẽ trả về users có id tương ứng
// src/users/users.controller.ts
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(+id);
}
Router nhận tham số id động, được chuyển đến và thực thi bởi findOne controller. Vì User model có id là integer nên tham số id cần được chuyển thành một số bằng toán tử +
// src/users/users.service.ts
findOne(id: number) {
return this.prisma.user.findUnique({where: {id}});
}
Kết quả:
Define POST /users endpoint
Đây là endpoint để tạo 1 user mới tưong ứng với create:
// src/users/users.controller.ts
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
Nó mong đợi các đối số phù hợp với CreateArticleDto trong phần request body.
DTO(Data Transfer Object)) là một đối tượng xác định cách dữ liệu sẽ được gửi qua mạng. Ban đầu, CreateArticleDto là một class trống. Ta sẽ thêm các thuộc tính vào nó để xác định định dạng của dữ liệu đầu vào.
Ở đây mình sẽ import package class-validator và class-transformer để dùng các hàm validate có sẵn:
yarn add class-validator class-transformer
// src/users/dto/create-user.dto.ts
import { IsString, IsEmail, MaxLength, IsBoolean } from 'class-validator';
export class CreateUserDto {
@IsString()
@MaxLength(255)
name: string;
@IsEmail()
email: string;
@IsString()
address?: string;
@IsBoolean()
isActive?: boolean = false;
}
// user service
create(createUserDto: CreateUserDto) {
this.prisma.user.create({ data: createUserDto });
}
Define PATCH /users/:id endpoint
Dùng để cập nhật các User hiện có:
// src/users/users.controller.ts
@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(+id, updateUserDto);
}
/// file user service
update(id: number, updateUserDto: UpdateUserDto) {
return this.prisma.user.update({ where: { id }, data: updateUserDto });
}
File update-user.dto.ts rule tương tự như create, hoặc bạn có thể thêm rule mới vào.
Kết quả update user 2
Define DELETE /users/:id endpoint
Dùng để xóa các User hiện có:
// src/users/users.controller.ts
@Delete(':id')
remove(@Param('id') id: string) {
return this.usersService.remove(+id);
}
remove(id: number) {
return this.prisma.user.delete({where: { id }});
}
Sau khi call api xóa user: DELETE: http://localhost:8000/users/1
, ta gọi api getAll sẽ chỉ có còn 1 user
Tổng kết
Chúc mừng! Bạn đã xây dựng API REST đơn giản nhất bằng NestJS. Trong 2 bài viết này, chúng ta đã đi qua các nội dung:
- Tổng quan về NestJS
- Khởi tạo 1 project NestJS
- Các bước xây dựng API REST với NestJS
- Tích hợp Prisma với NestJS
Một trong những điều có thể thấy là việc xây dựng API REST với NestJS và Prisma rất là đơn giản. Đây là một framework nodejs cực kỳ hiệu quả để nhanh chóng xây dựng các ứng dụng web có cấu trúc tốt, an toàn và và dễ bảo trì.
Cảm ơn các bạn đã đọc bài viết của mình. Hẹn gặp lại mọi người ở những chủ đề khác nhé. 👋👋👋
All rights reserved