GO RESTFUL — #6

Comparing Golang’s built-in HTTP server implementation with the most popular community package gorilla/mux

Minh-Phuc Tran
Level Up Coding
Published in
3 min readSep 12, 2019

--

This article is a summary of my experiments with Golang HTTP using both the builtin functionality and the most popular community-developed package to figure out an effective way to declare HTTP views and handle HTTP requests.

Builtin net/http package

Declare handlers

The net/http package contains all utilities needed to accept requests and handle them dynamically. We can register handlers with http.HandleFunc. The handler’s first parameter takes a string path to match, and the second parameter is a function to execute when that path is matched.

http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Go RESTful Series")
}

The matching algorithm is a prefix match, so the above declaration will route every request to the inline anonymous function. That is, since it’s only /, all routes will match it.

Read request

Every handler function receives a *http.Request as the second parameter, which is a struct instance pointer containing all information related to the request.

r.Method  // request method
r.URL // request URL
r.Header // request headers
r.Body // request body

Refer here for full http.Request API reference.

Write the response

Every handler function receives a http.ResponseWriter as the first parameter, which exposes APIs for writing the response’s headers and body. It implements io.Writer interface so that we can write the response similar to writing to files/stdout, etc.

// Set header
w.Header().Set("Some-Header", "value")
// Write using standard write method in fmt package.
fmt.Fprintf(w, "Body content")
// Write body will automatically write all previous-set header fields.

Start the server

In order to run the above code, we need to start the server.

http.ListenAndServe(":80", nil)

This will start the default HTTP server with default routes that we set using http.HandleFunc. If you want to create a new server and manage it in your own, please refer here, for the sake of this article, the default server is sufficient.

Community-developed packages

Go’s net/http package has already provided a decent number of APIs for writing HTTP applications. However, there’s one thing that it doesn’t do very well which is complex request routing like segmenting a request URL into single parameters. Fortunately, there’s a very popular community-developed package that handles that responsibilities named gorilla/mux.

Import

import "github.com/gorilla/mux"

Refactoring the code to use gorilla/mux

To apply gorilla/mux, we need to make some updates to the previous implementation.

// Create a new mux router.
r := mux.NewRouter()
// Replace http.HandleFunc by router.HandleFunc.
r.HandleFunc("/", handler)
// Replace 2nd parameter by the configured mux router.
http.ListenAndServe(":80", r)

Declare complex routes

With gorilla/mux, we can declare complex routes with variables, constrain routes with methods, etc.

r.HandleFunc("/users/", listUsers).Methods(http.MethodGet)
r.HandleFunc("/users/", createUser).Methods(http.MethodPost)
r.HandleFunc("/users/{userId}/", getUser).Methods(http.MethodGet)
r.HandleFunc("/users/{userId}/", updateUser).Methods(http.MethodPut)
r.HandleFunc("/users/{userId}/", deleteUser).Methods(Http.MethodDelete)

Refer here for full gorilla/mux API reference.

Get captured variables

We declared routes with variables, we should be able to capture the values of those variables in handlers.

func handler(w http.ResponseWriter, r *http.Request) {
// mux.Vars(r) returns all values captured in the request URL.
vars := mux.Vars(r)
// vars is a dictionary whose key-value pairs are variables' name-value pairs.
fmt.Fprintf(w, "User %s\n", vars["userId"])
}

As you can see, the standard HTTP server implementation in Go is already powerful. By using gorilla/mux we are able to get an even simpler interface for dealing with complex routing and managing requests.

--

--

Software Engineer. Documenting my journey at 𝐩𝐡𝐮𝐜𝐭𝐦𝟗𝟕.𝐜𝐨𝐦