Installing httprouter
httprouter is an open source Go package and can be installed using the go get command. Let us see the installation and basic usage in the steps given as follows:
- Install httprouter using this command:
go get github.com/julienschmidt/httprouter
We can import the library in our source code, like this:
import "github.com/julienschmidt/httprouter"
- The basic usage of httprouter can be understood through an example.
Let us write a REST service in Go that provides two things:
- Gets the Go compiler version
- Gets the content of a given file
We need to use a system package called os/exec to fetch the preceding details.
- The os/exec package has a Command function, using which we can make any system call and the function signature is this:
// arguments... means an array of strings unpacked as arguments
// in Go
cmd := exec.Command(command, arguments...)
- The exec.Command function takes the command and an additional argument's array. Additional arguments are the options or input for the command. It can then be executed by calling the Output function, like this:
out, err := cmd.Output()
- This program uses httprouter to create the service. Let us create it at the following path:
touch -p $GOPATH/src/github.com/git-user/chapter2/httprouterExample/main.go
The program's main function creates two routes and two function handlers. The responsibilities of function handlers are:
- To get the current Go compiler version
- To get the contents of a file
The program is trying to implement a REST service using httprouter. We are defining two routes here:
- /api/v1/go-version
- /api/v1/show-file/:name
package main
import (
"fmt"
"io"
"log"
"net/http"
"os/exec"
"github.com/julienschmidt/httprouter"
)
func main() {
router := httprouter.New()
router.GET("/api/v1/go-version", goVersion)
router.GET("/api/v1/show-file/:name", getFileContent)
log.Fatal(http.ListenAndServe(":8000", router))
}
:name is a path parameter. The basic Go router cannot define these special parameters. By using httprouter, we can match the REST methods. In the main block, we are matching GET requests to their respective routes.
Now we are coming to the implementation of three handler functions:
func getCommandOutput(command string, arguments ...string) string {
out, _ := exec.Command(command, arguments...).Output()
return string(out)
}
func goVersion(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
response := getCommandOutput("/usr/local/go/bin/go", "version")
io.WriteString(w, response)
return
}
func getFileContent(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
fmt.Fprintf(w, getCommandOutput("/bin/cat", params.ByName("name")))
}
exec.Command takes the bash command and respective options as its arguments and returns an object. That object has an Output method that returns the output result of command execution. We are utilizing this utility getCommandOutput function in both goVersion and getFileContent handlers. We use shell command formats such as go --version and cat file_name in handlers.
Now create two new files in the same directory. These files will be served by our file server program. You can create any custom files in this directory for testing:
Latin.txt:
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu.
Greek.txt:
Ο? δ? Φο?νι?ε? ο?τοι ο? σ?ν Κ?δμ? ?πι??μενοι.. ?σ?γαγον διδασ??λια ?? το?? ?Ελληνα? ?α? δ? ?α? γρ?μματα, ο?? ??ντα πρ?ν ?Ελλησι ?? ?μο? δο??ειν, πρ?τα μ?ν το?σι ?α? ?παντε? χρ?ωνται Φο?νι?ε?· μετ? δ? χρ?νου προβα?νοντο? ?μα τ? ?ων? μετ?βαλον ?α? τ?ν ?υ?μ?ν τ?ν γραμμ?των. Περιο??εον δ? σ?εα? τ? πολλ? τ?ν χ?ρων το?τον τ?ν χρ?νον ?Ελλ?νων ?Ιωνε?· ο? παραλαβ?ντε? διδαχ? παρ? τ?ν Φοιν??ων τ? γρ?μματα, μεταρρυ?μ?σαντ?? σ?εων ?λ?γα ?χρ?ωντο, χρε?μενοι δ? ???τισαν, ?σπερ ?α? τ? δ??αιον ??ερε ?σαγαγ?ντων Φοιν??ων ?? τ?ν ?Ελλ?δα, ?οινι??ια ?ε?λ?σ?αι.
Now run the program with this command. This time, instead of firing a curl command, let us use the browser as our output for GET. Windows users may not have curl as the first-hand application. They can use API testing software such as the Postman client while developing the REST API. Take a look at the following command:
go run $GOPATH/src/github.com/git-user/chapter2/httprouterExample/main.go
The output for the first GET request looks like this:
curl -X GET http://localhost:8000/api/v1/go-version
The result will be this:
go version go1.13.5 darwin/amd64
The second GET request requesting Greek.txt is:
curl -X GET http://localhost:8000/api/v1/show-file/greek.txt
Now, we will see the file output in Greek:
Ο? δ? Φο?νι?ε? ο?τοι ο? σ?ν Κ?δμ? ?πι??μενοι.. ?σ?γαγον διδασ??λια ?? το?? ?Ελληνα? ?α? δ? ?α? γρ?μματα, ο?? ??ντα πρ?ν ?Ελλησι ?? ?μο? δο??ειν, πρ?τα μ?ν το?σι ?α? ?παντε? χρ?ωνται Φο?νι?ε?· μετ? δ? χρ?νου προβα?νοντο? ?μα τ? ?ων? μετ?βαλον ?α? τ?ν ?υ?μ?ν τ?ν γραμμ?των. Περιο??εον δ? σ?εα? τ? πολλ? τ?ν χ?ρων το?τον τ?ν χρ?νον ?Ελλ?νων ?Ιωνε?· ο? παραλαβ?ντε? διδαχ? παρ? τ?ν Φοιν??ων τ? γρ?μματα, μεταρρυ?μ?σαντ?? σ?εων ?λ?γα ?χρ?ωντο, χρε?μενοι δ? ???τισαν, ?σπερ ?α? τ? δ??αιον ??ερε ?σαγαγ?ντων Φοιν??ων ?? τ?ν ?Ελλ?δα, ?οινι??ια ?ε?λ?σ?αι.
The endpoint /api/v1/show-file/ we defined in the exec example is not so efficient. Using httprouter, we can build advanced and performance-optimized file servers. In the next section, we'll learn how to do that.