Getting started with Go for JavaScript Developers

Recently I have been learning Go and wanted to write this guide to help other JavaScript/Node developers who want to learn Go save some headache. Basically in this article we are going to learn the equivalents of npm, nvm, npm install -g, npm install package -S, and npm install.

TL;DR

  • goenv: similar to nvm, used to manage installed Go versions
  • govendor: similar to npm, used to manage dependencies for projects
  • govendor fetch <package>: similar to npm install <package> -S, used to install a package for a project
  • govendor sync: similar to npm install, used to install all the packages defined in the vendor.json file
  • govendor init: similar to npm init -y, used to create the vendor and vendor/vendor.json file.
  • vendor/vendor.json: similar to package.json, used to specify the dependencies for a project
  • go get <package>: similar to npm i <package> -g
  • go install .: similar to npm i -g, used to compile a project and add a binary globally accessible

Overview

In this article we are going to do the following:

  • Install goenv to manage Go versions
  • Set up a Go Workspace
  • Set up PATHS
  • Make a simple project and use govendor to manage dependencies

Installing goenv

goenv is similar to nvm in that it allows you to install different versions of Go. The best way to install goenv is to clone it from the repo into ~/.goenv:

git clone https://github.com/syndbg/goenv.git ~/.goenv

After cloning the repo, add the following to your ~/.bash_profile file to set up goenv:

export GOENV_ROOT="$HOME/.goenv"
export PATH="$GOENV_ROOT/bin:$PATH"
export PATH="$HOME/.goenv/shims:$PATH"
# keep this line empty (1) we will fill this in the next section
# keep this line empty (2) we will fill this in the next section
eval "$(goenv init -)"

Then, restart your terminal window, or open a new terminal window and run the following:

goenv install --list

If goenv is setup properly, you should see an output with all the Go versions available. As of the time of writing this article, Go 1.9.4 is the latest version available, so we are going to install that:

goenv install 1.9.4

After the installation is complete, run the following to set 1.9.4 as the global version

goenv global 1.9.4
goenv rehash

Then run the following to make sure that Go is set up properly:

go env
go version

In the output, make sure that the GOROOT is set properly:

GOROOT="~/.goenv/versions/1.9.4"

The GOROOT should be set to ~/.goenv/versions/<current-version-using/

Set up Workspace

Go projects follow a certain folder structure and convention which are collectively referred to as a Workspace. By default the Workspace is set to ~/go but we are going to set it to a custom path ~/mygo. So go ahead and create that folder:

mkdir ~/mygo

Now, we have to add two entries to our ~/.bash_profile to set GOPATH and add GOPATH/bin to the list global system binaries:

export GOPATH="$HOME/mygo" # <-- (1) SET GOPATH to our workspace in ~/mygo
export PATH=$PATH:$(go env GOPATH)/bin # <-- (2) Add ~/mygo/bin to the path resolved globally

Now the bottom of your ~/.bash_profile should look like the following:

export GOENV_ROOT="$HOME/.goenv"
export PATH="$GOENV_ROOT/bin:$PATH"
export PATH="$HOME/.goenv/shims:$PATH"
export GOPATH="$HOME/mygo" # <-- (1) SET GOPATH to our workspace in ~/mygo
export PATH=$PATH:$(go env GOPATH)/bin # <-- (2) Add ~/mygo/bin to the path resolved globally
eval "$(goenv init -)"

Now that we have configured our Workspace we are ready to play with some code.

Making a Simple Go Project

Install govendor

First we are going to install the govendor package to help us manage our dependencies:

go get -u github.com/kardianos/govendor

After running that you should see the following folders created in your Workspace:

├── bin
│   ├── govendor
├── pkg
│   └── darwin_amd64
│       ├── github.com
└── src
    ├── github.com
        ├── kardianos
        └── pkg

Now if you run govendor -version you should see an output telling you the version of govendor that's installed. If you see an output you should be good to go to the next section.

Create a Hello World Project

Our Hello World project is going to make an http call to a public endpoint and log the results to the console. Run the following to set up the project and the necessary files:

mkdir -p ~/mygo/src/github/myusername/hello-go && cd $_
govendor init
touch .gitignore .go-version app.go

After running the above commands one after the other, you should have a folder structure like the following:

~/mygo/src/github/myusername/hello-go

├── .gitignore
├── .go-version
├── app.go
└── vendor
    └── vendor.json

Open the .go-version and add the following line:

1.9.4

This will indicate that this project will be using Go version 1.9.4. Then open your .gitignore file and add the following to ignore the vendor folder except the vendor.json file:

.gitignore

vendor/*
!vendor/vendor.json

Next, we are going to use govendor to "install" gorequest. Gorequest is an http client that simplifies calling API endpoints that speak JSON:

govendor fetch github.com/parnurzeal/gorequest

After running the above, you should see that the dependencies have been added to the vendor/vendor.json file and the packages have been added to the vendor folder. After installing gorequest, we are going to update the app.go to make a GET request and show the results in the console:

app.go

package main
import(
  "fmt"
  "github.com/parnurzeal/gorequest"
)

func main() {
  request := gorequest.New()
  url := "https://jsonplaceholder.typicode.com/posts/1"
  resp, _, errs := request.Get(url).End()
  fmt.Println(resp, errs)
}

Then run go run app.go and you should see the result of the GET request in the console. And if you want the binary to be added to your $GOPATH/bin folder, run go install. After running that you should be able to run hello-go anywhere on your system by simply invoking the binary hello-go.

Conclusion

When I started playing with Go I was assuming that the setup would take me 10 minutes, but I wanted a setup similar to Node's nvm and npm. I could have simply installed the Go binary and not worried about anything, but I wanted to learn how to set up a project that could potentially be deployed to production with proper dependency and Go version management. Installing goenv and a global version of Go with goenv was pretty easy but I got confused with the way that goenv handles GOPATH and GOROOT variables. I assumed that once I use goenv I don't have to worry about the GOPATH values. But even if you use goenv you should still manage your GOPATH and your Go workspace by yourself. I'm still exploring goenv and I'm curious to know how you can do something similar to npm and nvm where you switch your Node version and all the globally installed packages would respect that change.