October 17, 2020

Accessing your database from inside an HTTP handler in Go

Note: While this is interesting to learn more about creating closures, it was pointed out to me that there is a better way to do this. Look at this next post to learn more about it.

Writing my last project backend in Go, I was confronted with how to actually write my HTTP handlers.

The main issue I encountered was how to get the database handle in the handler so that I could actually use it for incoming requests. Since you usually have to respect a given interface, you cannot just add new arguments to the handling function.

Thanks to Mat Ryer (@matryer), I found a solution that I’ve been using ever since: returning the handler (see this blog post for more good tips).

The idea is to have one function returning an other one, called a closure. This allows us to access the variables outside the returned function without actually passing them as an argument to it.

Here’s a very simple (and incomplete) example, using gin-gonic as a router:

// HandleGetUser will search a user by its username, and return its data if it exists
// Store is an interface allowing to get elements from the database
func HandleGetUser(store Store) func(c *gin.Context) {
    // We return a function that matches the interface needed by the router
	return func(c *gin.Context) {
		username := c.Param("username")
	    // But can still use the database interface within the returned function
		u, err := store.GetUserByUsername(username)
		if err != nil {
			c.JSON(404, gin.H{"error": "Could not find user with this username"})
			return
		}
		c.JSON(200, u)
	}
}

You can also use this method to initialize some data at handler creation if needed, by just declaring it before you return the function.

Do you have any other way to get this done ? How can this be improved ? What are the pitfalls of this method ?

If you want more details or more examples about this method, reach out to me on twitter or by email !

Copyright Marin Gilles 2019-2020