Service Layer
In this section, we'll dive into the creation of the HauntedHousesService
, a crucial component in
our Python web application for managing haunted houses. The service layer is responsible for
handling the business logic related to haunted houses.
Understanding the Service Layer
The service layer acts as a bridge between the controller (which handles HTTP requests) and the repository (which deals with data storage). It encapsulates the business logic and ensures that the controllers remain lightweight and focused on handling user input.
Haunted Houses Service
We'll walk through the step-by-step process of creating the HauntedHousesService
provider.
This service class will act as the business logic layer for managing haunted houses in our API.
Importing Dependencies
from .repository import HauntedHousesRepository, HauntedHouse
We begin by importing the required modules. The service relies on the
HauntedHousesRepository
to interact with the data.
The HauntedHousesService
Class
The first thing we need in our service is a reference to the repository. We'll use dependency injection to inject the repository into the service.
from .repository import HauntedHousesRepository, HauntedHouse
class HauntedHousesService:
"""The haunted houses service"""
repository: HauntedHousesRepository # 💉 pest will know how to inject this!
Get a List of Haunted Houses
In our API, we will have a GET /haunted-houses
endpoint that returns a list of haunted houses.
Let's create a method in our service to serve this purpose.
from .repository import HauntedHousesRepository, HauntedHouse
class HauntedHousesService:
"""The haunted houses service"""
repository: HauntedHousesRepository # 💉 pest will know how to inject this!
def get_houses(self) -> list[HauntedHouse]:
"""Get all haunted houses"""
return self.repository.get_all_houses()
The get_houses
method simply delegates the call to the repository wich returns a list of
HauntedHouse
objects.
Get a Single Haunted House
We'll also need a method to get a single haunted house by its ID. Let's create a method for that.
from .repository import HauntedHousesRepository, HauntedHouse
class HauntedHousesService:
"""The haunted houses service"""
repository: HauntedHousesRepository # 💉 pest will know how to inject this!
def get_houses(self) -> list[HauntedHouse]:
"""Get all haunted houses"""
return self.repository.get_all_houses()
def get_house_by_id(self, house_id: int) -> HauntedHouse | None:
"""Get a haunted house by ID"""
return self.repository.get_house_by_id(house_id)
Create a New Haunted House
In order to provide the necessary business logic for creating a new haunted house, we'll need to
create a create_house
method in our service.
from .repository import HauntedHousesRepository, HauntedHouse
class HauntedHousesService:
"""The haunted houses service"""
repository: HauntedHousesRepository # 💉 pest will know how to inject this!
def get_houses(self) -> list[HauntedHouse]:
"""Get all haunted houses"""
return self.repository.get_all_houses()
def get_house_by_id(self, house_id: int) -> HauntedHouse | None:
"""Get a haunted house by ID"""
return self.repository.get_house_by_id(house_id)
def create_house(self, house: HauntedHouse) -> HauntedHouse:
"""Create a new haunted house"""
return self.repository.create_house(house)
Update an Existing Haunted House
The update_house
method will be responsible for updating an existing haunted house.
from .repository import HauntedHousesRepository, HauntedHouse
class HauntedHousesService:
"""The haunted houses service"""
repository: HauntedHousesRepository # 💉 pest will know how to inject this!
def get_houses(self) -> list[HauntedHouse]:
"""Get all haunted houses"""
return self.repository.get_all_houses()
def get_house_by_id(self, house_id: int) -> HauntedHouse | None:
"""Get a haunted house by ID"""
return self.repository.get_house_by_id(house_id)
def create_house(self, house: HauntedHouse) -> HauntedHouse:
"""Create a new haunted house"""
return self.repository.create_house(house)
def update_house(self, house_id: int, updated_house: HauntedHouse) -> HauntedHouse | None:
"""Update an existing haunted house"""
return self.repository.update_house(house_id, updated_house)
Delete a Haunted House
Finally, we'll need to be able to delete a haunted house. We'll create a delete_house
method for
that.
from .repository import HauntedHousesRepository, HauntedHouse
class HauntedHousesService:
"""The haunted houses service"""
repository: HauntedHousesRepository # 💉 pest will know how to inject this!
def get_houses(self) -> list[HauntedHouse]:
"""Get all haunted houses"""
return self.repository.get_all_houses()
def get_house_by_id(self, house_id: int) -> HauntedHouse | None:
"""Get a haunted house by ID"""
return self.repository.get_house_by_id(house_id)
def create_house(self, house: HauntedHouse) -> HauntedHouse:
"""Create a new haunted house"""
return self.repository.create_house(house)
def update_house(self, house_id: int, updated_house: HauntedHouse) -> HauntedHouse | None:
"""Update an existing haunted house"""
return self.repository.update_house(house_id, updated_house)
def delete_house(self, house_id: int) -> None:
"""Delete a haunted house by ID"""
self.repository.delete_house(house_id)
Dependency Injection
pest framework uses modular dependency injection. The providers are registered by the modules and injected in controllers and other providers. In this case, we are injecting the repository into the service. This means that we will need to register the repository as a provider in the module.
When we talked about the HauntedHousesModule
, we mentioned that we will be
comming back to it later. Now is the time to do that.
from pest import module
from .repository import HauntedHousesRepository
@module(
providers=[HauntedHousesRepository],
)
class HauntedHousesModule:
pass
And now that we are here, we can also register the HauntedHousesService
as a provider in the
module.
from pest import module
from .haunted_houses_service import HauntedHousesService
from .repository import HauntedHousesRepository
@module(
providers=[HauntedHousesService, HauntedHousesRepository],
)
class HauntedHousesModule:
pass
We will use our service as a provider for our controller in the next section.
Conclusion
In this section, we've covered the step-by-step process of creating the HauntedHousesService
class
within the pest framework. This service class acts as the core business logic layer, providing
methods for handling haunted house-related operations.
We also learned about dependency injection and how to register providers in the module. In the next
section, we'll create the HauntedHousesController
and learn how we can use our service in the
controller to handle HTTP requests.