/ Getting Started

REST a little bit with Golang.

Today we are going write a simple hello world kind of RESTful service. It is almost identical to previous article except we will need to use a html router to handle and service incoming html requests. I have been using mux as a html router and I'm kinda happy with it. We can get it using go get -u github.com/gorilla/mux.

Let's start with the console example, we had defined a parameter named name with type of string, well with this exercise we will look for a param called port. It can be string but just for fun, we will read it as an integer. To do so we need to replace the

   var name = flag.String("name", "world", "name defaults to world")

with this

   var port = flag.Int("port", 8000, "port to serve to")

Once we have the port with us, we can parse the address were we want to serve using something like

   addr := fmt.Sprintf("127.0.0.1:%d", *port)

Next thing we want is an http server, we can easily create it using http package like following

   srv := &http.Server{
      Addr: addr,
   }

Server has a handler property which can be set to a http hander, in our case the handler is a mux router. Creating a mux router is easy

  r := mux.NewRouter()

The route has a whole bunch of methods which can be used to register routes, but for simplicity sake, we are going to just use one HandleFunc. A HandleFunc takes in url fragment as a first argument and a Handler function. A Handler function is any function having (w http.ResponseWriter, r *http.Request) signature, I believe I don't need to explain the signature, its pretty self explanatory. A typical Handler which returns a string looks like

func sayHello(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "Hello %s!!\n", name)
}

And as you might have guessed, a simple catch-all route with something like

r.HandleFunc("/", sayHello)

When the http.Server receives any incoming http traffic, it will pass on everything to the mux router and the router will match the route and forward the request to the respective registered handler.

If you want to accept any parameters, you can define them in the url itself like

r.HandleFunc("/{name}", sayHello)

This will match anything like /*, now inside the handler you can extract the parameter using mux.Vars(r). To put in the final nail, we can ask the server to listen by invoking srv.ListenAndServe().

A working hello-world example which takes the name from url might look like following:

Please note that error handler and other cool stuff has been skipped intentionally for brevity.

package main

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

	"github.com/gorilla/mux"
)

var port = flag.Int("port", 8000, "port to serve to")

func init() {
	flag.Parse()
}

func sayHello(w http.ResponseWriter, r *http.Request) {
	// Extract params from the request
	params := mux.Vars(r)
	// Extract the name
	name, found := params["name"]
	// If name param was not supplied, set default value to world
	if !found {
		name = "World"
	}
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "Hello %s!!\n", name)
}

func main() {
	// Build the address:port, if nothing was passed we have 8000 at
	// port and it would result in "127.0.0.1:8000"
	addr := fmt.Sprintf("127.0.0.1:%d", *port)
	srv := &http.Server{
		Addr: addr,
		// Good practice: enforce timeouts for servers you create!
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	// The router
	r := mux.NewRouter()

	// Handle everything that comes through "/"
	r.HandleFunc("/", sayHello)
	// Handle route with name provided
	r.HandleFunc("/{name}", sayHello)

	// Set the server handler to our mux router
	srv.Handler = r

	// Tell folks what address are we listning to
	fmt.Printf("Listining at %s\n", addr)
	// Log failures (if any)
	log.Fatal(srv.ListenAndServe())
}

You can run it with go run main.go. Notice as we are not passing any cli arguments, service will listen to 8000 by default.

Here you go, you have a basic app which reads port from cli and takes in a param from uri and responds with Hello (name/world)!!.

Full code is available at github

Cheers!

Dave Amit

Dave Amit

Howdy folks! I am Dave Amit, an accidental programmer, father to a lab puppy, hubby to a beautiful wife, addicted to puzzles & a noob blogger. This is my effort to simplify odd codes from the wild.

Read More