Repository pattern
Clean and maintainable projects require the presentation, application, and persistence layers be kept separate from each other. No one likes spaghetti code that mixes bits of direct data retrieval and bits of data processing. In our opinion, only two things are needed to create a clean design in terms of data.
First of all, the code that retrieves and writes data to the database for a given Domain object should be extracted as a separate service so that there is only one place to access the domain object data in the entire project - the data access layer.
Second, database implementation details should be hidden behind an abstraction - an interface. This approach keeps the code database-independent and resilient to future changes in the infrastructure, since one database can easily be replaced in the code by another by creating a new implementation of the same interface for a new database. In addition, working on interfaces rather than a specific implementation helps you focus on the domain rather than on how the data is stored.
Both of these things can be achieved by using the Repository pattern. It focuses on abstracting the data access layer and separating data storage from the specific database implementation.
In this tutorial we will show you how to create the correct data access layer using this design pattern.
Some people think there is no point in using a design pattern like Repository if your project is small. However, we strongly recommend using this pattern for any project that will work in a production environment. Adapting to changes is part of a programmer’s job, and with the Repository pattern and the loose coupling between the database part and the business logic, any code change is easier.
A Domain object represents a logical entity in the problem domain space and contains purely domain information. In our tutorial, the domain object is the Website
, which contains information about the name, address, and ranking of the site.
type Website struct {
ID int64
Name string
URL string
Rank int64
}
Below is the Website
Repository interface. Note that there are no database details in the Repository
definition. They are hidden in the specific implementation of the Repository
, which could be a PostgreSQLRepository
, MySQLRepository
, MemoryRepository
, etc.
type Repository interface {
Migrate(ctx context.Context) error
Create(ctx context.Context, website Website) (*Website, error)
All(ctx context.Context) ([]Website, error)
GetByName(ctx context.Context, name string) (*Website, error)
Update(ctx context.Context, id int64, updated Website) (*Website, error)
Delete(ctx context.Context, id int64) error
}