Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Hands-On RESTful Web Services with Go

You're reading from   Hands-On RESTful Web Services with Go Develop elegant RESTful APIs with Golang for microservices and the cloud

Arrow left icon
Product type Paperback
Published in Feb 2020
Publisher Packt
ISBN-13 9781838643577
Length 404 pages
Edition 2nd Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Naren Yellavula Naren Yellavula
Author Profile Icon Naren Yellavula
Naren Yellavula
Arrow right icon
View More author details
Toc

Table of Contents (16) Chapters Close

Preface 1. Getting Started with REST API Development 2. Handling Routing for our REST Services FREE CHAPTER 3. Working with Middleware and RPC 4. Simplifying RESTful Services with Popular Go Frameworks 5. Working with MongoDB and Go to Create a REST API 6. Working with Protocol Buffers and gRPC 7. Working with PostgreSQL, JSON, and Go 8. Building a REST API Client in Go 9. Asynchronous API Design 10. GraphQL and Go 11. Scaling our REST API Using Microservices 12. Containerizing REST Services for Deployment 13. Deploying REST Services on Amazon Web Services 14. Handling Authentication for our REST Services 15. Other Books You May Enjoy

Introducing gorilla/mux – a powerful HTTP router

The word Mux stands for the multiplexer. gorilla/mux is a multiplexer designed to multiplex HTTP routes (URLs) to different handlers. Handlers are the functions that can handle the given requests. gorilla/mux is a wonderful package for writing beautiful routes for our API servers.

gorilla/mux provides tons of options to control how routing is done to your web application. It allows a lot of features, such as:

  • Path-based matching
  • Query-based matching
  • Domain-based matching
  • Sub-domain-based matching
  • Reverse URL generation

Which type of routing to use depends on the types of clients requesting the server. We first see the installation and then a basic example to understand the gorilla/mux package.

Installing gorilla/mux

Follow these steps to install the mux package:

  1. You need to run this command in the Terminal (Mac OS X and Linux):
go get -u github.com/gorilla/mux
  1. If you get any errors saying package github.com/gorilla/mux: cannot download, $GOPATH not set. For more details see--go help gopath, set the $GOPATH environment variable using the following command:
export GOPATH=~/go
  1. As we discussed in Chapter 1, Getting Started with REST API Development, all the packages and programs go into GOPATH. It has three folders: bin, pkg, and src. Now, add GOPATH to the PATH variable to use the installed bin files as system utilities that have no ./executable style. Refer to the following command:
PATH="$GOPATH/bin:$PATH"
  1. These settings stay until you turn off your machine. So, to make it a permanent change, add the preceding line to your bash/zsh profile file:
vi ~/.profile
(or)
vi ~/.zshrc

We can import gorilla/mux in our programs, like this:

import "github.com/gorilla/mux"

Now, we are ready to go. Assuming gorilla/mux is installed, we can now explore its basics.

Fundamentals of gorilla/mux

The gorilla/mux package primarily helps to create routers, similar to httprouter. The difference between both is the attachment of a handler function to a given URL. If we observe, the gorilla/mux way of attaching a handler is similar to that of basic ServeMux. Unlike httprouter, gorilla/mux wraps all the information of an HTTP request into a single request object.

The three important tools provided in the gorilla/mux API are:

  • The mux.NewRouter method
  • The *http.Request object
  • The *http.ResponseWriter object

The NewRouter method creates a new router object. That object basically maps a route to a function handler. gorilla/mux passes a modified *http.Request and *http.ResponseWriter object to the function handler. These special objects have lots of additional information about headers, path parameters, request body, and query parameters. Let us explain how to define and use different routers in gorilla/mux with two common types:

  • Path-based matching
  • Query-based matching

Path-based matching

A path parameter in the URL of an HTTP GET request looks like this:

https://example.org/articles/books/123

Since it is passed after the base URL and API endpoint, in this case https://example.org/articles/, they are called path parameters. In the preceding URL, books and 123 are path parameters. Let us see an example of how to create routes that can consume data supplied as path parameters. Follow these steps:

  1. Create a new file for our program at the following path:
touch -p $GOPATH/src/github.com/git-user/chapter2/muxRouter/main.go
  1. The idea is to create a new router, mux.NewRouter, and use it as a handler with in-built http.Server. We can attach URL endpoints to handler functions on this router object. The URL endpoints attached can also be regular expressions. The simple program to collect path parameters from a client HTTP request and return back the same looks like this:
package main

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

"github.com/gorilla/mux"
)

func ArticleHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Category is: %v\n", vars["category"])
fmt.Fprintf(w, "ID is: %v\n", vars["id"])
}

func main() {
r := mux.NewRouter()
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
srv := &http.Server{
Handler: r,
Addr: "127.0.0.1:8000",
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Fatal(srv.ListenAndServe())
}
  1. Now run the server using the following command in a shell:
go run $GOPATH/src/github.com/git-user/chapter2/muxRouter/main.go
  1. Make a curl request from another shell and we can get the output as follows:
curl http://localhost:8000/articles/books/123

Category is: books ID is: 123

This example shows how to match and parse path parameters. There is one more popular way to collect variable information from an HTTP request and that is with query parameters. In the next section, we see how to create routes that match HTTP requests with query parameters.

Query-based matching

Query parameters are variables that get passed along with the URL in an HTTP request. This is what we commonly see in a REST GET request. The gorilla/mux route can match and collect query parameters. See this following URL, for example:

http://localhost:8000/articles?id=123&category=books

It has id and category as query parameters. All query parameters begin after the ? character.

Let us modify our copy of our previous example into a new one with the name queryParameters/main.go. Modify the route object to point to a new handler called QueryHandler, like this:

// Add this in your main program
r := mux.NewRouter()
r.HandleFunc("/articles", QueryHandler)

In QueryHandler, we can use request.URL.Query() to obtain query parameters from the HTTP request. QueryHandler looks like this:

// QueryHandler handles the given query parameters
func QueryHandler(w http.ResponseWriter, r *http.Request) {
queryParams := r.URL.Query()
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Got parameter id:%s!\n", queryParams["id"][0])
fmt.Fprintf(w, "Got parameter category:%s!", queryParams["category"][0])
}

This program is similar to the previous example, but processes query parameters instead of path parameters.

Run the new program:

go run $GOPATH/src/github.com/git-user/chapter2/queryParameters/main.go

Fire a curl request in this format in a Terminal:

curl -X GET http://localhost:8000/articles\?id\=1345\&category\=birds

We need to escape special characters in the shell. If it is in the browser, there is no problem of escaping. The output looks like this:

Got parameter id:1345! 
Got parameter category:birds!

The r.URL.Query() function returns a map with all the parameter and value pairs. They are basically strings and, in order to use them in our program logic, we need to convert the number strings to integers. We can use Go's strconv package to convert a string to an integer, and vice versa.

We have used http.StatusOK to write a successful HTTP response. Similarly, use appropriate status codes for different REST operations. For example, 404 – Not found, 500 – Server error, and so on.

Other notable features of gorilla/mux

We have seen two basic examples. What next? The gorilla/mux package provides many handy features that makes an API developer's life easy. It gives a lot of flexibility while creating routes. In this section, we try to discuss a few important features. The first feature of interest is generating a dynamic URL with the reverse mapping technique.

In simple words, reverse mapping a URL is getting the complete API route for an API resource. Reverse mapping is quite useful when we share links to our web application or API. However, in order to create a URL from data, we should associate a Name with the gorilla/mux route. You can name a multiplexer route, like this:

r.HandlerFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
Name("articleRoute")

Now, we can get a dynamically generated API route by using the url method:

url, err := r.Get("articleRoute").URL("category", "books", "id", "123")
fmt.Printf(url.Path) // prints /articles/books/123

If a route consists of the additional path parameters defined, we should pass that data as arguments to the URL method.

The next important feature of a URL router is path prefix. A path prefix is a wildcard route for matching all possible paths. It matches all the routes to the API server, post a root word. The general use case of path prefixes is a static file server. Then, when we serve files from a static folder, the API paths should match to filesystem paths to successfully return file content.

For example, if we define /static/ as a path prefix, every API route that has this root word as a prefix is routed to the handler attached.

These paths are matched:

  • http://localhost:8000/static/js/jquery.min.js
  • http://localhost:8000/static/index.html
  • http://localhost:8000/static/some_file.extension

Using gorilla/mux's PathPrefix and StripPefix methods, we can write a static file server, like this:

r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("/tmp/static"))))

The next important feature is strict slash. A strict slash activated on a gorilla/mux router allows a URL to redirect to the same URL with / appended at the end and vice versa.

For example, let us say we have an /articles/ route that is attached to an ArticleHandler handler:

r.StrictSlash(true)
r.Path("/articles/").Handler(ArticleHandler)

In the preceding case, strict slash is set to true. The router then redirects even /articles (without '/' at the end) to the ArticleHandler. If it is set to false, the router treats both /articles/ and /articles as different paths.

The next important feature of a URL router is to match encoded path parameters. The gorilla/mux UseEncodedPath method can be called on a router to match encoded path parameters.

A server can receive encoded paths from a few clients. We can match the encoded path parameter, we can even match the encoded URL route and forward it to the given handler:

r.UseEncodedPath()
r.NewRoute().Path("/category/id")

This can match the following URL:

http://localhost:8000/books/2

As well as this:

http://localhost:8000/books%2F2

Where %2F2 stands for /2 in encoded form.

Its pattern-matching features and simplicity push gorilla/mux as a popular choice for an HTTP router in projects. Many successful projects worldwide are already using mux for their routing needs.

We are free to define routes for our application. Since routes are entry points to any API, developers should be careful about how they process the data received from a client. Clients can be attackers too, who can inject malicious scripts into the path or query parameters. That situation is called a security vulnerability. APIs are prone to a common application vulnerability called SQL injection. In the next section, we introduce it briefly and see possible countermeasure steps.

You have been reading a chapter from
Hands-On RESTful Web Services with Go - Second Edition
Published in: Feb 2020
Publisher: Packt
ISBN-13: 9781838643577
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime