ARTICLE AD BOX
Usually, you would create a single Postgres connection pool somewhere early in your app's startup code. Then you pass the connection pool as a dependency to your request handlers. Or to whatever abstractions you are using inside your request handlers, like repositories.
This approach works with the Echo framework just as well.
For example, you could create a request handler like so:
type GreetingHandler struct { db *pgxpool.Pool } func NewGreetingHandler(db *pgxpool.Pool) *GreetingHandler { return &GreetingHandler{db: db} } func (h *GreetingHandler) Handle(c echo.Context) error { ctx := context.Background() greeting := "" err := h.db.QueryRow(ctx, "SELECT 'Hello, world!'").Scan(&greeting) if err != nil { return c.String(http.StatusInternalServerError, err.Error()) } return c.String(http.StatusOK, greeting) }The GreetingHandler takes a pgxpool.Pool as a dependency. When handling a request in a goroutine, it calls h.db.QueryRow, which internally acquires a connection from the pool and executes the query.
Then you could wire the GreetingHandler to your Postgres connection pool and Echo instance as follows:
func main() { ctx := context.TODO() // Create a connection pool early before setting up request handlers. pool, err := pgxpool.New(ctx, os.Getenv("DB_URL")) if err != nil { log.Fatal(err) } defer pool.Close() // Make sure the database is reachable. if err := pool.Ping(ctx); err != nil { log.Fatal(err) } // Pass the connection pool as a dependency to the request handler. greeting := NewGreetingHandler(pool) // Register the request handlers to an Echo server, then start the server. e := echo.New() e.GET("/hello", greeting.Handle) if err := e.Start(":8080"); err != http.ErrServerClosed { log.Fatal(err) } }