A Service
Part of the TypeScript and NestJS section of Coddy's Node.js journey. Lesson 9 of 24.
The controller holds the tasks itself, so no other part of the app can reach them. Data and logic belong in a provider: a class Nest creates and hands to whoever asks for it.
@Injectable()
export class BooksService {
private books = [{ title: 'Dune' }];
}
@Controller('books')
export class BooksController {
constructor(private readonly booksService: BooksService) {}
}@Injectable() marks the class, and the module lists it in providers. A class asks for it by naming it in its constructor: this is dependency injection. private readonly in front of the parameter is TypeScript shorthand: it creates a field this.booksService and stores what Nest passes in. Nest reads the parameter's type, which the compiler keeps for decorated classes, creates one instance for the module that lists it, and passes that same instance to every class there that asks. The data is shared, and a test can pass in a fake instead.
This lesson opens with the controller already calling this.tasksService.
Challenge
EasyThis step opens the course’s prepared Nest task tracker project, rather than your project files from Status Codes and Errors (including src/tasks/tasks.controller.ts). Your earlier work stays in its own lesson. Read the supplied files before editing src/tasks/tasks.service.ts. This copy contains the Nest task routes, with the controller prepared to delegate to a service.
The tasks live inside the controller, so no other part of the app can reach them. Move them into a service: a class that owns the tasks, which Nest creates once and hands to every class that asks for it. The controller is already rewritten to call the service. Your job is to finish the service and connect the two.
- In
src/tasks/tasks.service.ts, mark the classTasksServicewith@Injectable(), from@nestjs/common. This lets Nest create it and hand it out. - In the same class, write a method
create(title). It builds a task with the next free id (one more than the largest id inthis.tasks), that title, anddone: false. It adds the task tothis.tasksand returns it. The controller'sPOST /taskscalls it with the title from the request body. - Write a method
remove(id), whereidis a number. When no task has that id, it must respond with 404, likefindOne: callthis.findOne(id)first, which throws. Then remove the task fromthis.tasks. It returns nothing. - In
src/tasks/tasks.module.ts, importTasksServicefrom./tasks.service, then add aproviderslist to the module, next tocontrollers, and putTasksServicein it. Nest only creates the classes a module lists there. - In
src/tasks/tasks.controller.ts, replace the comment insideTasksControllerwith a constructor that takes one parameter, writtenprivate readonly tasksService: TasksService. Nest sees the typeTasksServiceand passes in its one service. The wordsprivate readonlyin front of a parameter also create a field,this.tasksService, holding what was passed in. That is the name the methods below already use.
Try it: POST { "title": "Buy milk" } to /tasks. You get 201 and:
{ "id": 4, "title": "Buy milk", "done": false }Send GET /tasks: four tasks, with Buy milk last. Send DELETE /tasks/4: 204. Send DELETE /tasks/99: 404 with "message": "Task 99 not found".
Try it yourself
import { NotFoundException } from '@nestjs/common';
export interface Task {
id: number;
title: string;
done: boolean;
createdAt?: string;
}
// Make this class a provider that Nest can inject.
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;
}
// Write create(title) and remove(id) here.
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in TypeScript and NestJS
Practice on your own: Express playground