A mini-guide — Build a REST API as a Go microservice together with MySQL
Tags: go, beginners, sql, webdev
Published: 2019-08-11 20:26:29

I have recently found myself coding and deploying a lot of Go microservices, both at my day-job at Storytel and for my side-project [Wiseer](https://wiseer.io). In this mini-tutorial, I will create a simple REST-API with a MySQL database. The code for the complete project will be linked at the end of the article.

If you haven’t already done so I recommend taking the [Go Tour](https://tour.golang.org/) as a complementary to this article.

Let’s dive in!

---

# Setup the API

One of the first things to do is to choose a routing package. Routing is what connects an URL to an executable function. The [mux package](https://github.com/gorilla/mux) has served me well for _routing_, but there are other alternatives as well, with no real difference in performance. Such as [httprouter](https://github.com/julienschmidt/httprouter) and [chi](https://github.com/go-chi/chi). I will be using mux in this guide.

For the sake of simplicity, we will create a single endpoint that prints out a message.

{% gist https://gist.github.com/johan-lejdung/c429a550d1544fe54ac6eb224e4cafeb %}

The code above creates a *Router*, associates a URL with an [handler function](https://golang.org/pkg/net/http/#HandlerFunc) — postFunction in our case — and starts a server on port 8080 using that Router. 

Easy enough, huh? 🤠

---

# Database connection

Let's build on the code above by connecting it to a MySQL database. Go provides an [interface](https://golang.org/pkg/database/sql/) for SQL databases but requires a driver. I’m using [go-sql-driver](https://medium.com/r/?url=https%3A%2F%2Fgithub.com%2Fgo-sql-driver%2Fmysql) for this example.

{% gist https://gist.github.com/johan-lejdung/ecea9dab9b9621d0ceb054cec70ae676 %}

The code is placed in another package, called _db_, and assumes there is a database running on _localhost:3306_ with a database called _demo_. The returned database automatically handles a connection pool to the database.

Let us update the _postFunction_ from the previous code-snippet, to use this database.

{% gist https://gist.github.com/johan-lejdung/022f9be2080679f4772af1c0a879d5e1 %}

That’s really it! It’s rather simple, but there are a few issues with the code above and a few nice-to-haves missing. This is where it gets a bit trickier, but don't jump ship just yet! ⚓️

---

# Structs & Dependencies

If you’ve examined the code above, you might have noticed that we are opening the database on each API-call; even though the opened database [is safe for concurrent use](https://golang.org/pkg/database/sql/#Open). We need some dependency management to make sure we only open the database once, for this, we want to use a [struct](https://gobyexample.com/structs).

{% gist https://gist.github.com/johan-lejdung/99d52b9613150336f036362fbb23973e %}

We start by creating a new package, called _app_, to host our struct and it’s [methods](https://gobyexample.com/methods). Our *App* struct has two fields; a _Router_ and a _Database_ accessed at _ln 17_ and _ln 24_. We also set the returned status code manually at the end of the method at _ln 30_.

The main package and function also needs a few changes to make use of the new *App* struct. We remove the _postFunction_ and _setupRouter_ functions from this package, since it’s now in the app package. We are left with:

{% gist https://gist.github.com/johan-lejdung/1a65a12e5e2f79a0bb8a0bad96d04b49 %}

To make use of our new struct, we open a database and a new _Router_. Then we insert both of them into the fields of our new *App* struct.

Congratulations! You now have a connection to your database that will be used concurrently across all of your incoming API-calls 🙌

As a final step, we will add a _GET_-Method to our router setup and return the data in _JSON_. We start by adding a struct to fill our data with, and map the fields to _JSON_.

{% gist https://gist.github.com/johan-lejdung/2b9df2957c68bbee7c54d610c1a93453 %}

We follow that up with an expansion of the _app.go_ file, with a new method _getFunction_ that fetches and writes the data to the client response. The final file looks like this.

{% gist https://gist.github.com/johan-lejdung/78aeccbb4e81863f91235cb7c5695034 %}

---

# Database Migrations

We are going to add a final addition to the project. When a database is tightly coupled with an application or service you can save yourself _unfathomable levels of headache_ by properly handling migrations of said database. We are going to use [migrate](https://github.com/golang-migrate/migrate) for that, and expand our _db package_.


I'll go through the following, and admittedly long, gist below the embedded code.

{% gist https://gist.github.com/johan-lejdung/d13e9f455d28949af872de5d94df9c82 %}

Right after the opening of the database, we add another function call to _migrateDatabase_ that will in turn; start the migration process.

We will also add a MigrationLogger struct to handle the logging during the process, the code can be seen [here](https://github.com/johan-lejdung/go-microservice-api-guide/blob/master/rest-api/db/migrationlogger.go) and it's usage on _ln 45_.

The migrations are executed from normal sql-queries. The migration files are read from the folder seen at _ln 37_.

Each time the database is opened, all the unapplied database migrations will be applied. Thereby keeping the database up to date without any manuainterventionon.

This coupled with a _docker-compose_ file - containing the database - makes development on multiple machines dead-simple.

---

# Wrapping it up

So you've made it all the way down here 👏 👏

An undeployable microservice is of no use, therefore we will add a Dockerfile to package the application for easy distribution - _then I promise to let you go_.

{% gist https://gist.github.com/johan-lejdung/b409f3572bd03ad88507d88dd92d97d6 %}

The built image is a mere **10MB**! 😱

The code is available below.

{% github johan-lejdung/go-microservice-api-guide %}

---

I hope that you found this interesting and that you learned something! There are of course still things to improve upon, but that's where you and your creativity comes in 👍

If you liked this article sharing it with friends or on Twitter is greatly appreciated!

{% twitter 1160648900669267970 %}

I plan to cover more advanced topics in - hopefully shorter 😅 - articles. The topics I have thought of so far are; middleware usage, testing, dependency injection and service layers.