Building our first service – finding the Roman numeral
With the concepts we have built upto now, let us write our first basic REST service. This service takes the number range (1-10) from the client and returns its Roman string. Very primitive, but better than Hello World.
Design:
Our REST API should take an integer number from the client and serve back the Roman equivalent.
The block of the API design document may look like this:
Implementation:
Now we are going to implement the preceding simple API step-by-step.
As we previously discussed, you should set the GOPATH first. Let us assume the GOPATH is /home/naren/go. Create a directory called romanserver in the following path. Replace narenaryan with your GitHub username (this is just a namespace for the code belonging to different users):
Our main logic for the API server goes into this file. For now, we can create a data file which works as a data service for our main program. Create one more directory for packaging the Roman numeral data:
We are creating a map called Numerals. This map holds information for converting a given integer to its Roman equivalent. We are going to import this variable into our main program to serve the request from the client.
func main() { // http package has methods for dealing with requests http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { urlPathElements := strings.Split(r.URL.Path, "/") // If request is GET with correct syntax if urlPathElements[1] == "roman_number" { number, _ := strconv.Atoi(strings.TrimSpace(urlPathElements[2])) if number == 0 || number > 10 { // If resource is not in the list, send Not Found status w.WriteHeader(http.StatusNotFound) w.Write([]byte("404 - Not Found")) } else { fmt.Fprintf(w, "%q", html.EscapeString(romanNumerals.Numerals[number])) } } else { // For all other requests, tell that Client sent a bad request w.WriteHeader(http.StatusBadRequest) w.Write([]byte("400 - Bad request")) } }) // Create a server and run it on 8000 port s := &http.Server{ Addr: ":8000", ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } s.ListenAndServe() }
Always use the Go fmt tool to format your Go code.
Usage example: go fmt github.com/narenaryan/romanserver
Now, install this project with the Go command install:
go install github.com/narenaryan/romanserver
This step does two things:
Compiles the package romanNumerals and places a copy in the $GOPATH/pkg directory
Places a binary in the $GOPATH/bin
We can run the preceding API server as this:
$GOPATH/bin/romanserver
The server is up and running on http://localhost:8000. Now we can make a GET request to the API using a client like Browser or the CURL command. Let us fire a CURL command with a proper API GET request.
Request one is as follows:
curl -X GET "http://localhost:8000/roman_number/5" # Valid request
The response is as follows:
HTTP/1.1 200 OK Date: Sun, 07 May 2017 11:24:32 GMT Content-Length: 3 Content-Type: text/plain; charset=utf-8
"V"
Let us try a few incorrectly formed requests.
Request two is as follows:
curl -X GET "http://localhost:8000/roman_number/12" # Resource out of range
The response is as follows:
HTTP/1.1 404 Not Found Date: Sun, 07 May 2017 11:22:38 GMT Content-Length: 15 Content-Type: text/plain; charset=utf-8
404 - Not Found
Request three is as follows:
curl -X GET "http://localhost:8000/random_resource/3" # Invalid resource
The response is as follows:
"HTTP/1.1 400 Bad request Date: Sun, 07 May 2017 11:22:38 GMT Content-Length: 15 Content-Type: text/plain; charset=utf-8 400 - Bad request
Our little Roman numerals API is doing the right thing. The right status codes are being returned. That is the point all API developers should keep in mind. The client should be informed why something went wrong.