-
Notifications
You must be signed in to change notification settings - Fork 4
Container Resolving
Package /app/container
Catalyst uses a simple container to hold resolved dependencies.
The container is nothing more than a struct that has three major components.
- Adapters (wrappers around third party packages)
- Repositories (database access)
- Services (access to third party web APIs)
type Container struct {
Adapters Adapters
Repositories Repositories
Services Services
}Each of these components is in turn a struct that contains fields whose data types are interfaces. This is very important. If you don't have interface types for these fields your dependencies will be tightly coupled. We use interface types to enable dependency inversion.
For an example the Adapters struct looks like this.
type Adapters struct {
DB adapters.DBAdapterInterface
DBTrans adapters.DBTxAdapterInterface
Log adapters.LogAdapterInterface
Validator adapters.ValidatorAdapterInterface
}Note that all data types are interfaces.
What is meant by the term resolution of dependencies.
Let's take the Adapters struct above as the example. Notice that all data types of this struct are interfaces. Let's look at one such interface DBAdapterInterface.
type DBAdapterInterface interface {
// Query runs a query and return the result.
Query(ctx context.Context, query string, parameters map[string]interface{}) ([]map[string]interface{}, error)
// NewTransaction creates a new database transaction.
NewTransaction() (*sql.Tx, error)
// Destruct will close the database adapter releasing all resources.
Destruct()
}Now you can bind any object that implements the DBAdapterInterface to the DB filed of the Adapters struct (i.e. MySQLAdapter, PostgresAdapter). This is how you achieve coding to interface in other parts of the code.
Currently all resolved dependencies return a singleton. It is very important to remember this. Because if you change an internal property value of a dependency in one request it will be there for all subsequent requests as well.
The order that you resolve these dependencies matter. First you resolve low level dependencies and then move on to high level dependencies.
Most of the time a higher level dependency will use a lower level dependency. So it is important to have the low level dependency ready when requested by the higher level dependency.
For an example consider a repository. A repository will need a DBAdapter to connect to the database. So you will have to resolve the DBAdapter before resolving the repository.
Catalyst handle this by resolving dependencies in the following order.
- Resolve adapters
- Resolve repositories
- Resolve services