Một dịch vụ
Thuộc phần TypeScript và NestJS trong hành trình Node.js của Coddy. Bài học 9 trên 24.
Bộ điều khiển tự giữ các công việc, nên không phần nào khác của ứng dụng có thể truy cập chúng. Dữ liệu và logic thuộc về một provider: một lớp mà Nest tạo ra và chuyển cho bất kỳ nơi nào yêu cầu.
@Injectable()
export class BooksService {
private books = [{ title: 'Dune' }];
}
@Controller('books')
export class BooksController {
constructor(private readonly booksService: BooksService) {}
}@Injectable() đánh dấu lớp này, còn module liệt kê lớp đó trong providers. Một lớp yêu cầu provider bằng cách ghi tên nó trong hàm khởi tạo: đây là tiêm phụ thuộc. private readonly đứng trước tham số là cú pháp rút gọn của TypeScript: nó tạo trường this.booksService và lưu vào đó giá trị Nest truyền vào. Nest đọc kiểu của tham số, được trình biên dịch giữ lại cho các lớp có trang trí, tạo một instance cho module liệt kê lớp đó rồi truyền cùng instance ấy cho mọi lớp trong module yêu cầu nó. Dữ liệu được chia sẻ, và một bài kiểm thử có thể truyền vào một đối tượng giả.
Bài học này bắt đầu với bộ điều khiển đã gọi this.tasksService.
Thử thách
DễBước này mở dự án theo dõi công việc Nest đã chuẩn bị sẵn trong khóa học, thay vì các tệp dự án của bạn từ phần Mã trạng thái và lỗi (bao gồm src/tasks/tasks.controller.ts). Phần bạn làm trước đó vẫn nằm trong bài học riêng. Đọc các tệp được cung cấp trước khi chỉnh sửa src/tasks/tasks.service.ts. Bản sao này có các tuyến công việc Nest, với controller đã được chuẩn bị để chuyển việc xử lý cho một service.
Các công việc nằm bên trong controller, nên những phần khác của ứng dụng không thể truy cập chúng. Hãy chuyển chúng vào một service: một lớp sở hữu các công việc, được Nest tạo một lần rồi cung cấp cho mọi lớp cần đến nó. Controller đã được viết lại để gọi service. Bạn cần hoàn thiện service và kết nối hai phần này.
- Trong
src/tasks/tasks.service.ts, đánh dấu lớpTasksServicebằng@Injectable()từ@nestjs/common. Việc này cho phép Nest tạo lớp và cung cấp nó. - Trong cùng lớp đó, viết phương thức
create(title). Phương thức này tạo một công việc với id trống tiếp theo (lớn hơn id lớn nhất trongthis.tasksmột đơn vị), tiêu đề đó vàdone: false. Thêm công việc vàothis.tasksrồi trả về công việc đó. Controller gọi phương thức này từPOST /tasksvới tiêu đề lấy từ nội dung yêu cầu. - Viết phương thức
remove(id), trong đóidlà một số. Nếu không có công việc nào mang id đó, phương thức phải phản hồi bằng mã 404, giống nhưfindOne: trước tiên gọithis.findOne(id), phương thức này sẽ ném ngoại lệ. Sau đó xóa công việc khỏithis.tasks. Phương thức không trả về gì. - Trong
src/tasks/tasks.module.ts, nhậpTasksServicetừ./tasks.service, rồi thêm danh sáchprovidersvào module, bên cạnhcontrollers, và đặtTasksServicevào đó. Nest chỉ tạo những lớp được module liệt kê tại đó. - Trong
src/tasks/tasks.controller.ts, thay chú thích bên trongTasksControllerbằng hàm khởi tạo nhận một tham số, được viết làprivate readonly tasksService: TasksService. Nest nhận biết kiểuTasksServicevà truyền vào service duy nhất của lớp này. Các từprivate readonlyđặt trước một tham số cũng tạo ra một thuộc tính,this.tasksService, để lưu giá trị được truyền vào. Đây là tên mà các phương thức bên dưới đã dùng.
Thử nhé: Gửi POST với nội dung { "title": "Buy milk" } đến /tasks. Bạn sẽ nhận được mã 201 và:
{ "id": 4, "title": "Buy milk", "done": false }Gửi GET /tasks: bạn sẽ thấy bốn công việc, trong đó Buy milk nằm cuối cùng. Gửi DELETE /tasks/4: mã 204. Gửi DELETE /tasks/99: mã 404 với "message": "Task 99 not found".
Tự làm thử
import { NotFoundException } from '@nestjs/common';
export interface Task {
id: number;
title: string;
done: boolean;
createdAt?: string;
}
// Biến lớp (class) này thành provider để Nest có thể tiêm vào.
export class TasksService {
private tasks: Task[] = [
{ id: 1, title: 'Write the README', done: true, createdAt: '2026-01-05T09:00:00.000Z' },
{ id: 2, title: 'Fix the login bug', done: false, createdAt: '2026-01-06T14:30:00.000Z' },
{ id: 3, title: 'Plan the sprint', done: false, createdAt: '2026-01-07T08:15:00.000Z' },
];
findAll(done?: string): Task[] {
if (done === undefined) {
return this.tasks;
}
return this.tasks.filter((task) => task.done === (done === 'true'));
}
findOne(id: number): Task {
const task = this.tasks.find((task) => task.id === id);
if (!task) {
throw new NotFoundException(`Task ${id} not found`);
}
return task;
}
// Viết create(title) và remove(id) ở đây.
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong TypeScript và NestJS
1Nest cơ bản
Lớp và phương thứcXin chào, NestĐăng ký controller4Bộ bảo vệ, bộ lọc và bộ đánh chặn
Bộ bảo vệ2Nhà cung cấp
Đầu vào của hàm khởi tạoMột dịch vụĐăng ký nhà cung cấpTự luyện tập: Playground Express