Hanami: Entities, Repositories, and Representers
Introduction
Hanami is a modern web framework for Ruby that emphasizes simplicity, performance, and maintainability. It follows the principles of Domain-Driven Design (DDD) and separates the concerns of the application into different components. Three crucial components in Hanami are entities, repositories, and representers.
Entities
Definition:
- Entities are the core objects in the domain model of a Hanami application. They represent business logic and domain-specific rules.
Characteristics:
- Immutable: Entities in Hanami are immutable by default. This means that once an entity is created, its state cannot be changed.
- Business Logic: They encapsulate the core business logic and validation rules.
- Plain Ruby Objects: Entities are plain Ruby objects (POROs) without any dependency on external frameworks or libraries.
Example:
class User < Hanami::Entity
attributes do
attribute :id, Types::Int
attribute :name, Types::String
attribute :email, Types::String
attribute :created_at, Types::Time
attribute :updated_at, Types::Time
end
def full_name
"#{first_name} #{last_name}"
end
endUse Case:
- Use entities to represent and enforce the rules and logic of your business domain.
Repositories
Definition:
- Repositories provide an abstraction layer for data persistence. They handle the interactions with the database, such as querying, inserting, updating, and deleting records.
Characteristics:
- Data Access Layer: They act as the data access layer, providing a clean separation between the domain logic and database operations.
- CRUD Operations: Repositories offer methods for Create, Read, Update, and Delete (CRUD) operations.
- Query Interface: They provide a query interface to retrieve data from the database.
Example:
class UserRepository < Hanami::Repository
def find_by_email(email)
users.where(email: email).one
end
def all_users
users.to_a
end
endUse Case:
- Use repositories to manage database interactions and keep database-specific logic out of the domain logic.
Representers
Definition:
- Representers are responsible for defining how entities are serialized and deserialized. They manage the transformation of data between entities and external representations such as JSON or XML.
Characteristics:
- Serialization/Deserialization: They handle the conversion of entities to and from external formats.
- Flexible: Representers can be customized to include or exclude certain attributes and to format data as needed.
- Integration with APIs: Representers are useful for creating APIs where data needs to be exchanged in specific formats.
Example:
class UserRepresenter < Hanami::Representer
property :id
property :name
property :email
property :created_at
property :updated_at
end
# Usage
user = User.new(id: 1, name: 'John Doe', email: 'john.doe@example.com')
user_representer = UserRepresenter.new(user)
user_representer.to_jsonUse Case:
- Use representers to manage the presentation layer, ensuring that data is properly formatted when interacting with external systems or APIs.
Summary
In Hanami, entities, repositories, and representers play distinct but complementary roles in the architecture of an application:
- Entities: Represent the core business logic and domain rules. They are immutable and encapsulate domain-specific behavior.
- Repositories: Serve as the data access layer, providing methods to interact with the database. They abstract the persistence layer and offer CRUD operations.
- Representers: Handle the serialization and deserialization of entities, managing the transformation of data for external representations such as JSON or XML.
By separating these concerns, Hanami ensures a clean, maintainable codebase that adheres to the principles of Domain-Driven Design and promotes a clear separation of concerns.