DEV Community

Cover image for Understanding Dependency Injection in NestJS with a Book Service Example
Abhinav
Abhinav

Posted on

Understanding Dependency Injection in NestJS with a Book Service Example

Dependency Injection (DI) in NestJS simplifies the process of managing dependencies between services and classes. Let’s explore it using a BookService example to demonstrate how DI works in NestJS. πŸš€


🎯 Scenario

We want to build an application that:

  1. Retrieves a list of books from a database. πŸ“–
  2. Formats the books for display. ✨

We’ll use the following services:

  1. BookService: Handles book-related logic. πŸ› οΈ
  2. DatabaseService: Handles database interactions. πŸ’Ύ

πŸ› οΈ Step 1: Creating the DatabaseService

The DatabaseService simulates retrieving data from a database.

import { Injectable } from '@nestjs/common';

@Injectable()
export class DatabaseService {
  private books = [
    { id: 1, title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },
    { id: 2, title: '1984', author: 'George Orwell' },
    { id: 3, title: 'To Kill a Mockingbird', author: 'Harper Lee' },
  ];

  getAllBooks() {
    return this.books;
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ› οΈ Step 2: Creating the BookService

The BookService depends on the DatabaseService to retrieve books and then formats the output.

import { Injectable } from '@nestjs/common';
import { DatabaseService } from './database.service';

@Injectable()
export class BookService {
  constructor(private readonly databaseService: DatabaseService) {}

  getFormattedBooks() {
    const books = this.databaseService.getAllBooks();
    return books.map((book) => `${book.title} by ${book.author}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

Here, the DatabaseService is injected into the BookService through the constructor. πŸ”—


πŸ“¦ Step 3: Registering Services in a Module

Both services need to be registered as providers in a module. πŸ—‚οΈ

import { Module } from '@nestjs/common';
import { BookService } from './book.service';
import { DatabaseService } from './database.service';

@Module({
  providers: [BookService, DatabaseService],
  exports: [BookService], // Exporting BookService for use in other modules
})
export class BookModule {}
Enter fullscreen mode Exit fullscreen mode

🌐 Step 4: Using the BookService in a Controller

We can now use the BookService in a controller to expose the functionality through an API.

import { Controller, Get } from '@nestjs/common';
import { BookService } from './book.service';

@Controller('books')
export class BookController {
  constructor(private readonly bookService: BookService) {}

  @Get()
  getBooks() {
    return this.bookService.getFormattedBooks();
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ Step 5: Adding the Controller to the Module

Update the BookModule to include the controller. πŸ“‘

import { Module } from '@nestjs/common';
import { BookService } from './book.service';
import { DatabaseService } from './database.service';
import { BookController } from './book.controller';

@Module({
  providers: [BookService, DatabaseService],
  controllers: [BookController],
})
export class BookModule {}
Enter fullscreen mode Exit fullscreen mode

πŸ› οΈ How Dependency Injection Works Here

  1. DatabaseService:

    • Declared as a provider using the @Injectable() decorator. πŸ› οΈ
    • Registered in the module. βœ…
    • Injected into the BookService. πŸ”—
  2. BookService:

    • Declared as a provider using the @Injectable() decorator. πŸ› οΈ
    • Injected into the BookController. πŸ”—
  3. IoC Container:

    • NestJS automatically resolves and injects the dependencies (DatabaseService β†’ BookService β†’ BookController). πŸ€–

✨ Example Output

When you make a GET request to /books, the response would look like:

[
  "The Great Gatsby by F. Scott Fitzgerald",
  "1984 by George Orwell",
  "To Kill a Mockingbird by Harper Lee"
]
Enter fullscreen mode Exit fullscreen mode

πŸŽ‰ Advantages of DI in NestJS

  1. Loose Coupling: BookService doesn’t need to know how DatabaseService works. πŸ”—
  2. Reusability: Services like DatabaseService can be reused across the app. ♻️
  3. Testing: Mock services can be injected during testing for isolated unit tests. πŸ§ͺ

πŸš€ Summary

Dependency Injection in NestJS automates the creation and wiring of dependencies. By using decorators like @Injectable(), @Module(), and constructor injection, we can build scalable and maintainable applications. πŸ› οΈ

With this approach, we’ve created a clean and reusable architecture for the BookService example, demonstrating the power and simplicity of DI in NestJS. πŸ“šβœ¨

Top comments (0)