Building Microservices in Go: REST APIs - HTTP Handlers
Tags: go, microservices, rest
Published: 2021-05-27 23:35:29

When building Microservices the _de facto_ way to do it is to use both HTTP, as the protocol, and REST, as the way to represent resources. HTTP is literally the foundation of the World Wide Web and it is supported by multiple programmings in one way or another, so using HTTP is a no brainer because it could be used by any Frontend and Backend code with few to no external dependencies.

REST is an acronym for **REpresentational State Transfer** coined by [Roy Fielding](https://roy.gbiv.com/) and introduced in his [doctoral dissertation](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm), it is an architectural style that defines guidelines when building web services, it's not a standard but it does use standards like HTTP (and its verbs to represent actions) and payload/message formats (like JSON or XML), to mention a few.

This is the first of a series of posts covering steps for building REST APIs in Go.

> **Disclaimer:** This post includes Amazon affiliate links. If you click on one of them and you make a purchase I'll earn a commission. Please notice your final price **is not** affected at all by using those links.

---

## Introduction to HTTP Handlers

Go includes all the necessary building blocks for implementing Webservices in its standard library, including things like HTTP Servers, different multiplexers and way to define HTTP handlers, as well as way to render content in different encodings like JSON or XML, something like the following works for creating an HTTP server:

```go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Path: %s!", r.URL.Path[1:])
	})

	http.ListenAndServe(":8080", nil)
}
```

Accessing it using `curl`: 

```go
❯ curl -X GET http://localhost:8080/resources
Path: resources!
```

Using the standard library to define our HTTP Resources definitely works, however one of the biggest difficulties when using the standard library is the need to add extra code to build handlers that happen to have the same base path or require variables as pattern matching.

For example, assuming we need to define resources for `/resources`, `/resources/{id}` and `/resources/{id}/values` using the standard library will require us to define code to identify `/resources/{id}` and `/resources/{id}/values` **after** handling `/resources`.

This is better explained when requesting something like this:

```go
❯ curl -X GET http://localhost:8080/resources/1234/values
Path: resources/1234/values!
```

In this case our implemented handler needs to determine those arguments from the path itself.

For cases like this I recommend using a third party package called [`github.com/gorilla/mux`](https://github.com/gorilla/mux).

## Using github.com/gorilla/mux

`github.com/gorilla/mux` is a powerful URL router and dispatcher, it lets us implement handlers meant to be matched by different options, including paths, schemes or query values, to mention a few. To solve the problem we had before with the handler requiring us to define code to determine the other resources we could write something like:

```go
package main

import (
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gorilla/mux"
)

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/resources", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "/resources")
	})
	router.HandleFunc("/resources/{id:[0-9]+}", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "/resources/{id:[0-9]+}: %s!", mux.Vars(r)["id"])
	})
	router.HandleFunc("/resources/{id:[0-9]+}/values", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "/resources/{id:[0-9]+}/values: %s", mux.Vars(r)["id"])
	})

	srv := &http.Server{
		Handler:      router,
		Addr:         ":8080",
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	log.Fatal(srv.ListenAndServe())
}
```

Which then we can request using `curl` like we did before but this time the three different resources and clearly handled independently:

```go
❯ curl http://localhost:8080/resources
/resources

❯ curl http://localhost:8080/resources/123
/resources/{id:[0-9]+}: 123!

❯ curl http://localhost:8080/resources/456/values
/resources/{id:[0-9]+}/values: 456
```

## Implementing resources

> The code used for this post is [available on Github](https://github.com/MarioCarrion/todo-api-microservice-example/tree/ccc21e67047827c12ecd31798a60d968cac26f48).

I previously mentioned _Hexagonal Architecture_ during the [Domain Driven Design and Project Layout](https://mariocarrion.com/2021/03/21/golang-microservices-domain-driven-design-project-layout.html) post, using that as base we can define a new type [`TaskHandler`](https://github.com/MarioCarrion/todo-api-microservice-example/blob/ccc21e67047827c12ecd31798a60d968cac26f48/internal/rest/task.go#L24-L26) that defines all the different nouns meant to represent our resources:

```go
func (t *TaskHandler) Register(r *mux.Router) {
	r.HandleFunc("/tasks", t.create).Methods(http.MethodPost)
	r.HandleFunc(fmt.Sprintf("/tasks/{taskId:%s}", uuidRegEx), t.task).Methods(http.MethodGet)
	r.HandleFunc(fmt.Sprintf("/tasks/{taskId:%s}", uuidRegEx), t.update).Methods(http.MethodPut)
}
```

The naming of those resources usually is defined as collections, in our case `/tasks`, and depending on the needs we could define subcollections to represent collections associated to an entity belonging to our parent collection, so an example of this would be a hypothetical resource called `/tasks/{taskId}/categories`.

In the context of our "To Do Microservice" domain we are defining three methods that map exactly to three different HTTP verbs and three different actions defined in our `TaskService` [Application Service](https://mariocarrion.com/2021/04/11/golang-microservices-application-domain-services.html), those HTTP verbs usually map to CRUD operations:

* POST -> Create
* GET -> Read
* PUT -> Update
* DELETE -> Delete

Therefore our type defined above is mapped like:

* `POST /tasks` -> `(*TaskHandler).create` used to create tasks,
* `GET /tasks/{id}` -> `(*TaskHandler).task` used to retrieve tasks by id, and 
* `PUT /tasks/{id}` -> `(*TaskHandler).update` used to update tasks by id
* We didn't implement `DELETE /tasks/{id}` this time, but in a [future commit](https://github.com/MarioCarrion/todo-api-microservice-example/blob/acbed018c6abb716cd84dffc1777f91dfb5e3dfa/internal/rest/task.go#L43) we will see it appear.

Implementing the required resources also requires us to define concrete types for handling requests and responses, the way I like to recommend implementing those is to define types with the following naming `<MethodName><ResourceName><Request|Response>`, for example the type representing the payload to create a `Task` via `create` would be:

```go
type CreateTasksRequest struct {
	Description string `json:"description"`
}
```

And the response type response from `task` would be:

```go
type GetTasksResponse struct {
	Task Task `json:"task"`
}
```

Although a bit repetitive defining concrete types for requests and responses allows us to define more rules to those values when defining our OpenAPI document, which will be discussed in future posts.

## Parting words

With this post we kick off the series describing the steps for building REST APIs, building HTTP-based webservices is relatively simple when using the standard library, however things could become difficult when trying to deal with nested or parametrized resources, in those cases using a third party package like `github.com/gorilla/mux` makes sense.

Because we are using Domain Driven Design together with the Hexagonal Architecture we can explicitly indicate types representing the resources we are trying to model, mapping HTTP verbs to concrete methods and defining specific types for requests and responses lets us pave the
way for changes we will need to add documentation via OpenAPI 3.

## Recommended Reading

If you're looking to sink your teeth into more REST and Web Programming I recommend the following books:

* [The Design of Web APIs (2019)](https://amzn.to/32yFwFe)
* [Go Web Programming (2016)](https://amzn.to/30euJ1U)
* [REST in Practice (2010)](https://amzn.to/3n6ztRZ)