Nest.js is a powerful and flexible framework for building server-side applications with TypeScript. It offers a wide range of features and tools that simplify the development process and improve code quality. In this tutorial, we will focus on Services and Providers in Nest.js, which are two key concepts that enable dependency injection and help keep your code organized and maintainable.


What are Services and Providers in Nest.js?

In Nest.js, a Service is a class that encapsulates some specific business logic or functionality that can be reused across different components of your application. For example, you might have a UserService that handles user authentication, or a ProductService that manages product data. Services can be injected into other classes or components using dependency injection, which makes it easy to manage dependencies and improve code organization.

A Provider is a class that provides a specific value or object instance that can be injected into other classes or components. Providers are typically used to create instances of Services or other objects that need to be shared across multiple components. For example, you might have a DatabaseProvider that creates a database connection and provides it to different Services in your application.


Creating a Service in Nest.js

To create a Service in Nest.js, you need to define a class that implements the business logic or functionality you want to encapsulate. Here's an example of a simple UserService that handles user authentication:

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

@Injectable()
export class UserService {
  private users = [
    { username: 'admin', password: 'password' },
    { username: 'user', password: '123456' },
  ];

  public authenticate(username: string, password: string): boolean {
    const user = this.users.find(u => u.username === username);
    if (!user) return false;
    return user.password === password;
  }
}

In this example, the UserService defines a private array of users that can be used for authentication. The authenticate method takes a username and password and checks if there is a matching user in the users array.

The @Injectable() decorator tells Nest.js that this class should be treated as a Service and can be injected into other components.


Using a Service in Nest.js

Once you have defined a Service in Nest.js, you can inject it into other classes or components that need to use its functionality. To inject a Service, you need to define a constructor that takes the Service as a parameter and add the @Inject() decorator to the parameter. Here's an example of a simple controller that uses the UserService for authentication:

import { Controller, Post, Body, HttpException, HttpStatus, Inject } from '@nestjs/common';
import { UserService } from './user.service';

@Controller()
export class AuthController {
  constructor(@Inject(UserService) private readonly userService: UserService) {}

  @Post('login')
  public login(@Body() body: { username: string, password: string }): string {
    const authenticated = this.userService.authenticate(body.username, body.password);
    if (!authenticated) {
      throw new HttpException('Invalid username or password', HttpStatus.UNAUTHORIZED);
    }
    return 'Welcome!';
  }
}

In this example, the AuthController defines a constructor that takes the UserService as a parameter and injects it using the @Inject() decorator. The login method takes a username and password from the request body and uses the UserService to authenticate the user. If the user is not authenticated, it throws an HttpException with a 401 status code.


Creating a Provider in Nest.js

To create a Provider in Nest.js, you need to define a class that provides a specific value or object instance that can be injected into other components. Here's an example of a simple DatabaseProvider that creates a database connection:

import { Injectable, Inject } from '@nestjs/common';
import { createConnection } from 'typeorm';

@Injectable()
export class DatabaseProvider {
public async getConnection() {
return createConnection({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'password',
database: 'mydatabase',
entities: [],
synchronize: true,
});
}
}

In this example, the DatabaseProvider defines a `getConnection` method that creates a new database connection using TypeORM. The configuration options for the connection are hard-coded in this example, but you could also load them from a configuration file or environment variables.

The `@Injectable()` decorator tells Nest.js that this class should be treated as a Provider and can be injected into other components.


Using a Provider in Nest.js

Once you have defined a Provider in Nest.js, you can inject it into other components that need to use its provided value or object instance. To inject a Provider, you need to define a constructor that takes the Provider as a parameter and add the `@Inject()` decorator to the parameter. Here's an example of a simple Service that uses the DatabaseProvider to get a database connection:

import { Injectable, Inject } from '@nestjs/common';
import { Connection } from 'typeorm';
import { DatabaseProvider } from './database.provider';

@Injectable()
export class UserService {
constructor(@Inject(DatabaseProvider) private readonly dbProvider: DatabaseProvider) {}

public async getUsers(): Promise<User[]> {
const connection = await this.dbProvider.getConnection();
const userRepository = connection.getRepository(User);
const users = await userRepository.find();
return users;
}
}

In this example, the UserService defines a constructor that takes the DatabaseProvider as a parameter and injects it using the `@Inject()` decorator. The `getUsers` method uses the DatabaseProvider to get a database connection, then uses TypeORM to get the UserRepository and fetch all users from the database.


Conclusion

Services and Providers are two key concepts in Nest.js that enable dependency injection and help keep your code organized and maintainable. Services encapsulate business logic or functionality that can be reused across different components of your application, while Providers provide specific values or object instances that can be injected into other components.

In this tutorial, we've shown you how to create and use Services and Providers in Nest.js with TypeScript. By leveraging these concepts, you can build scalable and maintainable server-side applications that are easy to test and extend.