Given the changes with Go Modules I wanted to document a brief getting started for Go projects, this will focus on building a minimal web service.

Before you start you will need to install Go, I recommend using homebrew or for ubuntu users Golang Backports, or as last resort grab it from the Go Downloads page.

So this looks like this for OSX.

brew install go

Or for ubuntu we add the PPA, then install golang 1.14 and update our path.

sudo add-apt-repository ppa:longsleep/golang-backports
sudo apt-get update
sudo install golang-1.14
echo 'export PATH=$PATH:/usr/lib/go-1.14/bin' >> ~/.bashrc
source ~/.bashrc

Now we should be able to run.

go version

Now navigate to where you build your projects, for me this is ~/Code/goprojects and make a folder. One thing to note here is that this goprojects folder is not in my $GOPATH as we are using modules.

cd ~/Code/goprojects
mkdir simple-go-service
cd simple-go-service

Before we start adding code lets initiliase our project, you should replace USERNAME with your github username, for me it is wolfeidau.

go mod init github.com/USERNAME/simple-go-service

Now for me I follow a pattern of storing the entry point in a cmd folder, this is done so I can easily customise the name of the binary as go uses the parent folder name executables.

mkdir -p cmd/simple-service
touch cmd/simple-service/main.go

Now add some code to the main.go you created in the previous command, this will listen on port :8000 for web requests.

package main

import (
	"io"
	"log"
	"net/http"
)

func main() {
	// Hello world, the web server

	helloHandler := func(w http.ResponseWriter, req *http.Request) {
		io.WriteString(w, "Hello, world!\n")
	}

	http.HandleFunc("/hello", helloHandler)
    log.Println("Listing for requests at http://localhost:8000/hello")
	log.Fatal(http.ListenAndServe(":8000", nil))
}

Now run this with the following command.

go run cmd/simple-service/main.go

This should print out a URL you can navigate to in your browser and see the classic Hello, world!.

Now from here you will want to setup an editor, I personnally use vscode which has really good support for golang once you add the go plugin.

From here I would recommend looking at something like echo which is a great web framework, it is well documented and has lots of great examples.

To add this library either just add the import in your editor, vscode will automatically trigger a download of libraries or run.

go get -u -v github.com/labstack/echo/v4

NOTE: We are using the v4 tagged import as we are using Go Modules, also I have also ensure this v4 tag is in the imports in the following example.

And update the main.go to use this great little REST crud example.

package main

import (
	"net/http"
	"strconv"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
)

type (
	user struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	}
)

var (
	users = map[int]*user{}
	seq   = 1
)

//----------
// Handlers
//----------

func createUser(c echo.Context) error {
	u := &user{
		ID: seq,
	}
	if err := c.Bind(u); err != nil {
		return err
	}
	users[u.ID] = u
	seq++
	return c.JSON(http.StatusCreated, u)
}

func getUser(c echo.Context) error {
	id, _ := strconv.Atoi(c.Param("id"))
	return c.JSON(http.StatusOK, users[id])
}

func updateUser(c echo.Context) error {
	u := new(user)
	if err := c.Bind(u); err != nil {
		return err
	}
	id, _ := strconv.Atoi(c.Param("id"))
	users[id].Name = u.Name
	return c.JSON(http.StatusOK, users[id])
}

func deleteUser(c echo.Context) error {
	id, _ := strconv.Atoi(c.Param("id"))
	delete(users, id)
	return c.NoContent(http.StatusNoContent)
}

func main() {
	e := echo.New()

	// Middleware
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	// Routes
	e.POST("/users", createUser)
	e.GET("/users/:id", getUser)
	e.PUT("/users/:id", updateUser)
	e.DELETE("/users/:id", deleteUser)

	// Start server
	e.Logger.Fatal(e.Start(":1323"))
}

Now run this with the following command.

go run cmd/simple-service/main.go

Hopefully you have managed to get this service running and started testing it with something like postman ๐ŸŽ‰.

For next steps I recommend reading How do I Structure my Go Project?.