Build your first API server with httprouter in Golang

Gaurav Singha Roy
4 min readSep 30, 2017

--

I turned into a Gopher abut 10 months ago and have never looked back. Like many other gophers, I quickly found the simple features of the language quite useful to quickly build fast, and scalable softwares. When I was initially picking up Go, I was playing around with different multiplexers available to be used as an API server. If you are coming from a Rails background like me, you probably would also have struggled in building all the Given features which one can get from Web Frameworks. Coming back to the multiplexers, I found 3 to be quite useful, viz., Gorilla mux, httprouter and bone (ordered in the ascending order of their performance). Even though bone had the best performance, and also it had a simpler handler signature, for me it still was not mature enough to be used in the production environment yet. So, I ended up using httprouter. In this tutorial, I would build a simple REST API server with httprouter.

In case you feel lazy and you just want the code, you can directly check my github repository here.

Let us begin. First create a basic endpoint

In the above snippet, Index is a handler function and needs to have three input parameters as input. This handler is then registered to the path GET /in the main function. Now compile and run your program and go to http://localhost:8080 to see your API server in action. Click here to get the code so far.

Now lets add a little bit of complexity to our API. We now have an entity called Book which can be uniquely identified with the field ISDN. So let us create a couple of more actions, viz., GET /books and GET /books/:isdn representing the Index and Show actions respectively. Our main.go file now looks like :

Now if you try to request GET https://localhost:8080/books, you get the following response

{
"meta": null,
"data": [
{
"isdn": "123",
"title": "Silence of the Lambs",
"author": "Thomas Harris",
"pages": 367
},
{
"isdn": "124",
"title": "To Kill a Mocking Bird",
"author": "Harper Lee",
"pages": 320
}
]
}

These were the two entries of books which we hardcoded into the main function. Check here to for the code so far.

Lets refactor our code a bit. So far we have all the code in just one file, main.go. Lets move them to separate files. We now have a directory :

.
├── handlers.go
├── main.go
├── models.go
└── responses.go

Lets move all the JSON response related structs to responses.go, the Handler functions to handlers.go and the Book struct to models.go. Check here to for the code so far. Now, lets jump on to write some tests. As you know, in Go the *_test.go files are for tests. So lets create a handlers_test.go.

We use the httptest package’s Recorder to mock the Handlers. Similarly you can also write tests for the handler BookShow .

Lets refactor a bit more. We still are defining all the routes in the main function, our handlers look a bit verbose and can be made a little DRY, we are still lacking some log messages in the terminal, and lets also add a BookCreate handler to create a new Book.

First, lets DRY out the handlers.go.

I created two functions, writeOKResponse for writing responses with StatusOK and a model or a slice of models returned in it, and writeErrorResponse which writes a JSON error as a response in case of any expected or unexpected errors. Like any good gopher, we should not panic. I also added a function called populateModelFromHandler which unmarshals the contents from the body to any model (struct) you want. In this case we are using in the BookCreate handler to populate a Book.

Now, lets take care of the logging. We simply create Logger function which wraps around the handler functions and prints log messages before and after execution of the handler function.

Lets take care of the routes now. First, define all the routes in one place, say routes.go.

Lets make a function NewRouter , which can be called from the main function, which reads all the routes defined above and returns a usable httprouter.Router. So create a file router.go. We will also wrap around the handlers with the newly created Logger function.

Your directory should now look like

.
├── handlers.go
├── handlers_test.go
├── logger.go
├── main.go
├── models.go
├── responses.go
├── router.go
└── routes.go

Check here for the full code base.

This should get you going to start writing your own API server. You would of course need to put your functionalities into different packages, so one good way could be

.
├── LICENSE
├── README.md
├── handlers
│ ├── books_test.go
│ └── books.go
├── models
│ ├── book.go
│ └── *
├── store
│ ├── *
└── lib
| ├── *
├── main.go
├── router.go
├── rotes.go
├── logger.go

You can also put handlers, models, All the routes functionalities under another package called app if you have a big monolithic server. Just keep in mind, go is not like Java or Scala and there cannot be cyclic package calls. So you have to take extra care with your package structure.

Thats all and hope this tutorial was useful. Cheers !

--

--

Gaurav Singha Roy

Experienced technical leader and work as a Staff+ software engineer. Passionate about the staff role, software engineering practices and mental health.