DEV Community

CK L
CK L

Posted on

Simple Golang + Mux Router API Service

Maybe you want to create a simple Golang REST API, to test the language out. This tutorial aims to build a simple API Service that returns a hardcoded json using the Mux Router library

Objectives

Create a simple API on a port that returns a { "hello": "world" } JSON

Setting up libraries and main.go

  1. Start by setting up the go modules
go mod init simple-backend
go get github.com/gorilla/mux # this is the mux library
Enter fullscreen mode Exit fullscreen mode
  1. Set up main.go
// main.go
package main

func main() {
  // to be filled later
}
Enter fullscreen mode Exit fullscreen mode

Your project folder structure should now look like this:

.
├── go.mod
├── go.sum
└── main.go
Enter fullscreen mode Exit fullscreen mode

Setting up app.go

We set up the app.go to house all the app's main logic, e.g. app.run() and app.initialiseRoutes() methods.

  1. Add app.go on the root directory level:
.
├── app.go # add here
├── go.mod
├── go.sum
└── main.go
Enter fullscreen mode Exit fullscreen mode
  1. Add the App type, which houses the mux router, and add the relevant methods run() and initialiseRoutes()
// app.go
package main

import (
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

// App export
type App struct {
    Router *mux.Router
}

// TODO: add handlers here

func (app *App) initialiseRoutes() {
  app.Router = mux.NewRouter()
  // TODO: add routes here
}

func (app *App) run() {
    log.Fatal(http.ListenAndServe(":8080", app.Router))
}

Enter fullscreen mode Exit fullscreen mode

We have a few TODO's to complete. Lets start by adding the handler and some helper functions for future use.

That being said, when the number of handlers grow, we will have to find a new folder for them to be in. For now though app.go should do just fine.

// TODO: add handlers here
func helloWorldHandler(w http.ResponseWriter, r *http.Request) {
    var response map[string]interface{}
    json.Unmarshal([]byte(`{ "hello": "world" }`), &response)
    respondWithJSON(w, http.StatusOK, response)
}

func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(code)
    json.NewEncoder(w).Encode(payload)
}
Enter fullscreen mode Exit fullscreen mode

Here the handler's function signature should match

func handlerFunc(w http.ResponseWriter, r *http.Request)

at least that is what the

mux.Router.HandleFunc(path, handlerFunc)

expects anyway.

On the other hand, the respondWithJSON() function helps us pass any struct over to the http.responseWriter to be sent back to the client. Anyway, for future handlers we decide to implement, we can always reuse this helper function to feed the structs back to the client.

  1. Finish up the initialiseRoutes() to use the handler function

Inside the initialiseRoutes() function, we add the routes.

func (app *App) initialiseRoutes() {
    app.Router = mux.NewRouter()
  // TODO: add routes here
    app.Router.HandleFunc("/", helloWorldHandler)
}
Enter fullscreen mode Exit fullscreen mode

We could add a few routes here as we wish, but here we add the helloWorldHandler to the path / so that the request localhost:8080 would be routed to the helloWorldHandler

The app.go should end up like below:

// app.go
package main

import (
    "encoding/json"
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

// App export
type App struct {
    Router *mux.Router
}

func helloWorldHandler(w http.ResponseWriter, r *http.Request) {
    var response map[string]interface{}
    json.Unmarshal([]byte(`{ "hello": "world" }`), &response)
    respondWithJSON(w, http.StatusOK, response)
}

func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(code)
    json.NewEncoder(w).Encode(payload)
}

func (app *App) initialiseRoutes() {
    app.Router = mux.NewRouter()
    app.Router.HandleFunc("/", helloWorldHandler)
}

func (app *App) run() {
    log.Fatal(http.ListenAndServe(":8080", app.Router))
}

Enter fullscreen mode Exit fullscreen mode

Finish up main.go

  1. Here we finish up our main.go, adding the run() and the initialiseRoutes() to the entrace function

The main.go should end up like so:

// main.go
package main

func main() {
    app := App{}
    app.initialiseRoutes()
    app.run()
}
Enter fullscreen mode Exit fullscreen mode

Start the server

...and we should be good to go! Now run the below command to start the server from the project root directory:

go run .
Enter fullscreen mode Exit fullscreen mode

or, you can build an executable and run it

go build 
./simple-backend # don't forget to put this inside your .gitignore!
Enter fullscreen mode Exit fullscreen mode

and, you can test the server using

curl localhost:8080
{"hello":"world"}
Enter fullscreen mode Exit fullscreen mode

Conclusion

...and there you have it! A simple Golang API server using the Mux router library.

However, in an actual application, the functionality would not be as simple as returning a mere "hello world" response. Next time, we will be improving on this project, tidying up the folder structure and adding more functionality to it.

Top comments (0)