Сервис
Часть раздела TypeScript и NestJS путешествия по Node.js на Coddy. Урок 9 из 24.
Контроллер хранит сами задачи, поэтому никакая другая часть приложения не может получить к ним доступ. Данные и логика должны находиться в провайдере: классе, который Nest создаёт и передаёт тому, кто его запрашивает.
@Injectable()
export class BooksService {
private books = [{ title: 'Dune' }];
}
@Controller('books')
export class BooksController {
constructor(private readonly booksService: BooksService) {}
}@Injectable() помечает класс, а модуль перечисляет его в providers. Класс запрашивает этот провайдер, указывая его в конструкторе: это внедрение зависимостей. private readonly перед параметром — это сокращённая запись TypeScript: она создаёт поле this.booksService и сохраняет в нём то, что передаёт Nest. Nest считывает тип параметра, который компилятор сохраняет для декорированных классов, создаёт один экземпляр для модуля, в котором он указан, и передаёт этот же экземпляр каждому классу в этом модуле, который его запрашивает. Данные общие, а в тест можно передать поддельный объект.
Этот урок начинается с контроллера, который уже вызывает this.tasksService.
Задание
ЛегкоНа этом шаге открывается подготовленный проект трекера задач на Nest для этого курса, а не файлы вашего проекта из урока Коды состояния и ошибки (включая src/tasks/tasks.controller.ts). Ваша предыдущая работа остаётся в своём уроке. Прочитайте предоставленные файлы, прежде чем редактировать src/tasks/tasks.service.ts. В этой копии есть маршруты задач Nest, а контроллер подготовлен для делегирования работы сервису.
Задачи находятся внутри контроллера, поэтому другие части приложения не могут получить к ним доступ. Переместите их в сервис: класс, который отвечает за задачи и который Nest создаёт один раз и передаёт каждому классу, который его запрашивает. Контроллер уже переписан для вызова сервиса. Ваша задача — завершить сервис и связать эти два компонента.
- В
src/tasks/tasks.service.tsпометьте классTasksServiceдекоратором@Injectable()из@nestjs/common. Это позволит Nest создать его и передавать его другим компонентам. - В том же классе напишите метод
create(title). Он создаёт задачу со следующим свободным идентификатором (на единицу больше наибольшего идентификатора вthis.tasks), указанным заголовком и значениемdone: false. Он добавляет задачу вthis.tasksи возвращает её. Контроллер вызывает этот метод дляPOST /tasks, передавая заголовок из тела запроса. - Напишите метод
remove(id), гдеid— число. Если задачи с таким идентификатором нет, метод должен возвращать ответ 404, какfindOne: сначала вызовитеthis.findOne(id), который выбросит исключение. Затем удалите задачу изthis.tasks. Метод ничего не возвращает. - В
src/tasks/tasks.module.tsимпортируйтеTasksServiceиз./tasks.service, затем добавьте в модуль списокprovidersрядом сcontrollersи поместите в негоTasksService. Nest создаёт только те классы, которые перечислены там в модуле. - В
src/tasks/tasks.controller.tsзамените комментарий внутриTasksControllerконструктором с одним параметром, записанным какprivate readonly tasksService: TasksService. Nest видит типTasksServiceи передаёт экземпляр сервиса. Словаprivate readonlyперед параметром также создают полеthis.tasksService, в котором хранится переданное значение. Это имя уже используется в методах ниже.
Проверьте: отправьте POST с телом { "title": "Buy milk" } на /tasks. Вы получите ответ 201 и:
{ "id": 4, "title": "Buy milk", "done": false }Отправьте GET /tasks: получите четыре задачи, последней будет Buy milk. Отправьте DELETE /tasks/4: получите ответ 204. Отправьте DELETE /tasks/99: получите ответ 404 с сообщением "message": "Task 99 not found".
Попробуйте сами
import { NotFoundException } from '@nestjs/common';
export interface Task {
id: number;
title: string;
done: boolean;
createdAt?: string;
}
// Сделайте этот класс провайдером, который Nest сможет внедрять.
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;
}
// Реализуйте здесь create(title) и remove(id).
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела TypeScript и NestJS
Потренируйтесь самостоятельно: Песочница Express