Welcome to this lesson on Providers in NestJS. So far, we've covered setting up a basic NestJS application and understanding its project structure. We also explored how controllers in NestJS handle requests. Today, we’ll dive into providers — a core concept in NestJS that helps manage and execute business logic.
Providers are a fundamental building block in NestJS applications. Understanding providers will help you build more modular, maintainable, and testable applications. There are many different kinds of providers in NestJS but we're going to learn about Services. We'll be focusing on a BookService
in this lesson which is responsible for providing Book
data.
In NestJS, a Service is a class that is decorated with the @Injectable()
decorator. Services are used to encapsulate and manage business logic, data processing, and any other operations that are not directly tied to handling requests (which is the role of controllers). By separating business logic into services, you promote a clean architecture where concerns are properly separated, making your application more modular and easier to maintain.
Dependency Injection (DI) is a pattern where an object receives its dependencies from an external source rather than creating them itself. This strategy makes it easier to manage and scale your application.
In NestJS, DI is built-in and allows you to inject services and other dependencies into your classes. This is done through the use of special decorators and the NestJS DI container.
Imagine you have a coffee shop, and each coffee machine needs a supply of coffee beans. With DI, instead of each machine fetching its beans, a central service provides beans to all machines. This simplifies management and ensures each machine gets what it needs efficiently.
Let's start by creating a service called BooksService
. This service will provide methods to retrieve information about books.
Here is the step-by-step code to create BooksService
:
TypeScript1import { Injectable } from '@nestjs/common'; 2import { Book, books } from './books.data'; 3 4@Injectable() 5export class BooksService { 6 getAllBooks(): Book[] { 7 return books; 8 } 9 10 getOneBook(id: string): Book { 11 return books.find(book => book.id === id); 12 } 13}
@Injectable()
: This decorator indicates that the class can be managed by the NestJS DI system.BooksService
: This class contains methods to get all books and to get a single book by its ID.getAllBooks()
: This method returns an array of books.getOneBook(id: string)
: This method returns a single book that matches the given ID.
Next, we need to use our BooksService
within a controller to handle incoming requests.
Here's the code to set up the BooksController
to receive an instance of BooksService
and use it in the GET handler:
TypeScript1import { Controller, Get } from '@nestjs/common'; 2import { Book } from './books.data'; 3import { BooksService } from './books.service'; 4 5@Controller('books') 6export class BooksController { 7 constructor(private readonly booksService: BooksService) {} 8 9 @Get() 10 findAll(): Book[] { 11 return this.booksService.getAllBooks(); 12 } 13}
@Controller('books')
: This decorator defines a controller that handles requests to the/books
route.BooksService
: TheBooksService
is injected into the controller via the constructor.@Get() findAll()
: This method handlesGET
requests to/books
and returns all books by callinggetAllBooks
fromBooksService
.
To fully integrate BooksService
and BooksController
into our application, we need to declare them in the BooksModule
module. We'll cover Modules later but for now, notice how we can define the BooksService
as a provider
in addition to the BooksController
which already existed from the previous lesson.
Here's the code for BooksModule
:
TypeScript1import { Module } from '@nestjs/common'; 2import { BooksController } from './books.controller'; 3import { BooksService } from './books.service'; 4 5@Module({ 6 controllers: [BooksController], 7 providers: [BooksService], 8}) 9export class BooksModule {}
@Module({})
: This decorator defines a module that groups related controllers and providers.controllers: [BooksController]
: This array lists all controllers in the module.providers: [BooksService]
: This array lists all providers in the module including our new service.
By declaring BooksService
and BooksController
in a module, NestJS can properly manage their lifecycle and dependencies.
In this lesson, we explored the concept of providers in NestJS and how to create and use them. We started by understanding what providers are and the role of dependency injection. We then created a BooksService
to fetch book data, integrated it with a controller, and finally declared them in a module.
Providers are essential for managing and structuring business logic within your application. In the upcoming practice exercises, you will get hands-on experience to reinforce your understanding of providers in NestJS. Keep these concepts in mind as they are crucial for building robust and maintainable applications.