Here will see how to pass a database to a service layer. Service layer will have interface. Look at our main function
func Run() error {
fmt.Println("Application start up")
database, err := db.NewDatabase()
if err != nil {
fmt.Println("Error creating database")
}
if err := database.MigrateDB(); err != nil {
fmt.Println("failed to migrate database")
}
cmtService := comment.NewService(database)
...................................................................................
...................................................................................
fmt.Println("successfully connected to database")
return nil
}
func main() {
fmt.Println("Go rest api")
if err := Run(); err != nil {
fmt.Println("returned error")
}
}
In the main function, we create a database object by calling the NewDatabase()
function. This function returns a pointer to a Database
struct which contains a pointer to a sqlx.DB
object. This sqlx.DB
object is the connection pool to the database.
Look at our Database struct
type Database struct {
//here DB is abstract of database and maintain a connection pool
Client *sqlx.DB
}
Then we pass this Database
object as an argument to the NewService()
function which returns a pointer to a Service
struct. In this way, we inject the database object into the service layer, making it available for use by the service layer.
Look at our NewService() constructor
type Store interface {
//repository layer should implement this
GetComment(context.Context, string) (Comment, error)
PostComment(context.Context, Comment) (Comment, error)
DeleteComment(context.Context, string) error
UpdateComment(context.Context, string, Comment) (Comment, error)
}
type Service struct {
Store Store
}
func NewService(store Store) *Service {
return &Service{
Store: store,
}
}
When we call a function in the service layer, it can then use the Store
interface to communicate with the database. The Store
interface defines the methods that the repository layer should implement to interact with the database. The Service
struct then uses these methods to perform various CRUD operations on the database.
So in summary, the database object is created in the main function and passed to the service layer through the NewService()
function. The service layer then uses the Store
interface to interact with the database through the repository layer.
Another summary
In our example, the Store interface is defined to be implemented by the Database
struct. The Database
struct has a field named db of type *sql.DB.
When we call NewService, we pass a Database
object which implements the Store interface. Since Database
has a db field of type *sql.DB, which satisfies the Store interface, we can pass the Database object to NewService.
So when NewService is called with a Database
object, it can access the db field of the Database object using the Store interface. This is possible because the Database
struct implements the Store interface, and the db field of the Database
struct is of type *sql.DB, which is what the Service methods expect to receive.