Skip to content

Providers and Injectables in PyNest 🏗️

Providers, also known as services or injectables, are fundamental in PyNest applications. They handle business logic and other functionalities, acting as dependencies that can be injected into other components like controllers. This guide explains what providers are, how to use them, how to import and export them in modules, and how to inject them into controllers and other services, with various examples.

What is a Provider?

In PyNest, a provider is a class annotated with the @Injectable decorator. This decorator makes the class available for dependency injection, allowing it to be injected into other classes such as controllers and services.

Defining a Provider

To define a provider, use the @Injectable decorator. This makes the class available for dependency injection within the module or globally if exported.

Example: Logger Service

logger_service.py

from nest.core import Injectable

@Injectable
class LoggerService:
    def log(self, message: str):
        print(f"LOG: {message}")

In this example, the LoggerService class is defined as a provider by using the @Injectable decorator. This class can now be injected into other classes within the same module or exported to be used in other modules.

Using Providers in Modules

Modules are used to group related providers, controllers, and other modules. Providers can be imported and exported in modules to be used across the application.

Example: S3 Module s3_module.py

from nest.core import Module
from .s3_service import S3Service
from src.providers.logger.logger_service import LoggerService
from src.providers.logger.logger_module import LoggerModule


@Module(
    providers=[S3Service, LoggerService],
    exports=[S3Service],
    imports=[LoggerModule],
)
class S3Module:
    pass

In this example:

The S3Module defines a module that provides the S3Service and exports it for use in other modules. It is also importing the LoggerModule to use the LoggerService.

Injecting Providers into Controllers and Services

Providers can be injected into controllers and other services using dependency injection. This is done by declaring the dependency in the constructor of the class where the provider is needed.

Example: S3 Service and Controller

s3_service.py

from nest.core import Injectable
from src.providers.logger.logger_service import LoggerService

@Injectable
class S3Service:

    def __init__(self, logger_service: LoggerService):
        self.logger_service = logger_service

    def upload_file(self, file_name: str):
        print(f"Uploading {file_name}")
        self.logger_service.log(f"Uploaded file: {file_name}")

In this Service, the LoggerService is injected into the S3Service via the constructor.

s3_controller.py

from nest.core import Controller, Post
from .s3_service import S3Service

@Controller('/s3')
class S3Controller:
    def __init__(self, s3_service: S3Service):
        self.s3_service = s3_service

    @Post('/upload')
    def upload_file(self, file_name: str):
        self.s3_service.upload_file(file_name)
        return {"message": "File uploaded successfully!"}

In these examples:

The S3Service is injected into the S3Controller via the constructor.

Importing and Exporting Providers

Providers can be shared between modules by importing and exporting them.

Example: Email Module

email_module.py

from nest.core import Module
from src.providers.s3.s3_module import S3Module
from src.providers.s3.s3_service import S3Service
from .email_service import EmailService

@Module(
    imports=[S3Module],
    providers=[EmailService, S3Service],
    exports=[EmailService],
)
class EmailModule:
    pass

In this example:

The EmailModule imports the S3Module to use the S3Service provided by it.

The EmailService is defined as a provider in the EmailModule and exported for use in other modules.

Conclusion

Providers are essential parts in PyNest applications, handling business logic and other functionalities. By defining, importing, exporting, and injecting providers, you can create modular and maintainable applications with clear separation of concerns. Understanding how providers work and how to use them effectively will help you build robust and scalable applications with PyNest.