Golang and AWS Lambda are two of the primary tools I use everyday for work, so when AWS announced that lambda would natively support Go earlier this year I was ecstatic. In this tutorial, I'll walk through how easy it is to deploy a fully functional API using these technologies and others by way of the serverless framework.

Disclaimer

This tutorial is designed to be deployed to AWS, and while the majority of resources should fall under the free tier, please be aware that this could be costing you actual money.

Some Background

So why is official support for Golang in AWS Lambda so great?

Well, firstly, building a Golang application is dead simple, and this makes deployment dead simple. The output of go build is a statically linked binary, and this is literally the only thing you need to deploy an application to lambda.

Second, Golang enjoys one of the lower cold start times of the currently supported languages, and is likely to improve on that mark in the future.

Also, sometimes you just get tired of javascript.

Setup

Before we get started, we need to prepare our environment. My machine is setup with the following:

In fact, even in this simple form, we are able to deploy the two functions to lambda and test them out. I like to add a new build target to the Makefile to facilitate this. Here's what that looks like:

Our Handler func is being executed on every lambda function invocation, always returning a static response.

Adding an API

Now that we're starting to get a feel for deploying and executing lambda functions with Golang, let's begin to introduce an API. First, we'll need to install some dependencies and remove the aws-lambda-go dependency.

You'll likely receive a warning from dep at this point indicating that the installed dependencies are not imported by your project, but we'll address that soon enough. Let's start by creating a new directory for our handler and removing the demo functions.

Telling that instance to run our foo function when it receives a GET at /foo.

The most interesting part is how we "start the engine". If the environment variable GIN_MODE is set to "release", we wrap our handler with the gateway package, which basically abstracts the API gateway syntax and allows us to focus on the server itself. Cool, right?

If GIN_MODE does not equal "release", we start an ordinary http server.

A few things to note on these changes. In the Makefile, we remove the old calls to go build and introduce a new one for our handler. In serverless.yml, we're again removing references to our previous functions and adding our handler.

The more interesting part is the addition of events. This block tells serverless what events need to take place in order to invoke our Lambda function. In this case, we're saying that we want our function to be invoked in response to API gateway receiving a GET request to /foo.

Be sure to take special care to note the endpoints section of the output. This is the public URL of your API gateway endpoint and should end in /dev/foo. Let's test that endpoint with curl (yours will be different).

Awesome! We've just deployed our first API written in Golang to Lambda, fronted by API gateway. From here, the world is your oyster.

Finished

In my next post, we'll look at how to extend our serverless configuration to add a DynamoDB table and integrate that into our API.

]]>

Intro

Golang is pretty hot right now. Over the past few weeks, I've been exploring implementing some of the cloud infrastracture I'd previously built with node in go, partly for fun, partly because go is fast. This led me to believe that setting up a basic REST service would make

Intro

Golang is pretty hot right now. Over the past few weeks, I've been exploring implementing some of the cloud infrastracture I'd previously built with node in go, partly for fun, partly because go is fast. This led me to believe that setting up a basic REST service would make for a great tutorial.

At the end, we will have a fully functioning REST service for serving basic CRUD on a user resource. Code for the final product can be found here.

This is the third and final entry in a series of high level tutorials on setting up a REST service using golang, focused on wiring up our previous webserver to a mongo backend.

Setup mgo

At the end of the last tutorial, we had a functioning, albeit useless, webserver offering some CRUD operations on a user resource. In this entry, we will be tying that to a mongodb backend for persistent data. If you don't have mongo installed on your system, you can find instructions here or install via brew.

The most popular mongo driver for golang is easily mgo. We'll be using two packages provided by mgo, mgo itself and bson. We need to grab each package to get going.

$ go get gopkg.in/mgo.v2
$ go get gopkg.in/mgo.v2/bson

We also need to establish a connection to mongo to provide to our controllers. Add the following function to our server.go.

Update the UserController struct

The first thing we need to do to our UserController is to extend the struct to contain a reference to a *mgo.Session so that our controller methods can access mongo. Update the UserController definition to match the following.

UserController struct {
session *mgo.Session
}

Next, we need to update our NewUserController function to receive a *mgo.Session and instantiate the controller with it. Update NewUserController to match the following.

Update the User Model

Before we start updating the controller methods to use mongo, we need to update our model to integrate with mgo. Similar to how we updated the user model to use a json struct tag for outputting JSON data, we need to add a struct tag to tell mgo how to store the user information.

You'll notice that we are importing only the bson package from mgo. The bson package provides an implementation of the bson specification for go. We use this to change the type of our Id field to a bson.ObjectId.

We also extend each field with a bson struct tag to describe the property name of the mongo document containing the user.

Update the POST Controller

Now that our model has been updated and our controller has a reference to an active mongo session, let's start integrating mongo into our service by updating the CreateUser method of our UserController. Update the method to the following.

Again, there a couple of significant changes. First, we are converting our id path parameter to a bson.ObjectId to be used to find the user. In the event that the id cannot be converted, we bail with a 404 Not Found. Second, we use our mongo session to find a user matching the provided id from the users collection. We also added an error check when we find the user to deliver a 404 Not Found.

As you can see, we are again getting an ObjectId out of the id path parameter, and bailing with a 404 if the id cannot by converted to an ObjectId. We then remove the document matching this id and deliver a 200.

We can test this by first deleting the user we created, then trying to fetch the user.

Great! We removed the user and confirmed that the user no longer exists.

Fin

This is end of the tutorial on adding a backend to our REST service, and also the end of the tutorial series in general. While there most certainly are many improvements to be made, such as adding some security and much better error handling, hopefully this high-level overview has been beneficial.

Resources

Intro

Golang is pretty hot right now. Over the past few weeks, I've been exploring implementing some of the cloud infrastracture I'd previously built with node in go, partly for fun, partly because go is fast. This led me to believe that setting up a basic REST service would make

Intro

Golang is pretty hot right now. Over the past few weeks, I've been exploring implementing some of the cloud infrastracture I'd previously built with node in go, partly for fun, partly because go is fast. This led me to believe that setting up a basic REST service would make for a great tutorial.

At the end, we will have a fully functioning REST service for serving basic CRUD on a user resource. Code for the final product can be found here.

This is the second in a series of high level tutorials on setting up a REST service using golang, focused on using public packages and defining a basic webserver.

Packages

Go allows for external packages to be accessed in your source via the import statement. These packages must be accessible somewhere in your GOPATH or GOROOT environment, depending on whether the packages come from a third party or the Go standard library, respectively. In the previous tutorial, you may have noticed that we imported the fmt package when we tested our setup. The fmt package is part of the standard library. You can find more standard library packages here.

Third party packages can be fetched via the go get command. There are a few special rules for fetching a remote package, described here, but for now we just need to understand the rules for packages publicly available on github. Put simply, any go package on github can fetched via the following.

$ go get github.com/USER/PROJECT

You'll notice there is no version information in the above command, which is another caveat of go. There are several solutions for this, such as using a makefile to set a temporary GOPATH within the application and checking dependencies into your source control. I've also grown fond of GoDep.

Router

Since we're trying to build out a webserver, let's find a router package. When searching for a go package to use, GoDoc is always a good place to start. There are many excellect candidates, but let's use the httprouter package. We first need to fetch the package with go get.

$ go get github.com/julienschmidt/httprouter

To get started, we first need to create a directory to host our application. If you followed along with the last tutorial, the following will get us started. Otherwise, setup a new directory somewhere in your GOPATH.

Here we are adding a new handler to respond to the "/test" route. Notice that the handler itself has a different signature than the standard http.HandlerFunc.

Also, we are able to respond to the request with fmt.Fprint. Strangely, if you look at the signature of fmt.Fprint, it shows the following.

func Fprint(w io.Writer, a ...interface{}) (n int, err error)

So how are we able to pass our instance of http.ResponseWriter to it as an io.Writer? Because io.Writer is an interface. Interfaces are implemented implicitly in go. In fact, http.ResponseWriter itself is an interface, which also satisfies the io.Writer interface.

And for the last interesting piece.

http.ListenAndServe("localhost:3000", r)

Here, as you can guess, we are firing up a webserver to listen on localhost:3000, using our router to handle requests. This is another instance where we can see the power of interfaces in go. http.ListenAndServe accepts an interface type http.Handler, which the author of httprouter provides as a convencience.

Let's go ahead and test our example server. First, fire it up.

$ go run server.go

Then, in another terminal, hit our router with a curl statement.

$ curl http://localhost:3000/test
Welcome!

Sweet!

Models

When building webapps in go, I tend to modularize the components as much as possible, both for testing purposes and readability. Models are one example of a piece of functionality I usually break into a separate package.

First, we need to create a directory within our application for the new package. Since I want it to be referred to as models, I'll name the directory the same. This is not required, but I find it to be a good convention.

$ mkdir models

Now let's add a file in the models directory to represent the structure of our user resource. I'll call it something crazy like user.go.

You'll notice two major changes. First, we added an import statement for our newly created models package. Second, we added a new handler to respond to "/user/:id" for retrieving a user. For those unfamiliar with this pattern, :id represents a parameter we can retrieve from the path, which we do to populate the Id field of our user. We also call json.Marshal on our user, which will decode our user into a JSON representation, and deliver that to the client.

Sweet! We have our example user. But do we really want to deliver the user with capitalized field names? Probably not. We could try to use lower case field names on the user struct, but then the fields will no longer be exported and available in our main package.

The documentation for the json package tells us that we can "alias" field names to be whatever we want using struct tags.

Controllers

One thing you may begin to notice is that our server.go is getting rather bloated with handlers. This is another piece of functionality I typically refactor into a package. Let's do that into a package called controllers.

Fin

That's the end of the tutorial on setting up a basic webserver with golang. We've created an httprouter instance, a model for our user resource, a controller for our user resource, and finally wired them all together.

Next time, we'll add a backend to get a true webservice feel. Check it out.

Resources

Intro

Golang is pretty hot right now. Over the past few weeks, I've been exploring implementing some of the cloud infrastracture I'd previously built with node in go, partly for fun, partly because go is fast. This led me to believe that setting up a basic REST service would make

Intro

Golang is pretty hot right now. Over the past few weeks, I've been exploring implementing some of the cloud infrastracture I'd previously built with node in go, partly for fun, partly because go is fast. This led me to believe that setting up a basic REST service would make for a great tutorial.

At the end, we will have a fully functioning REST service for serving basic CRUD on a user resource. Code for the final product can be found here.

This is the first in a series of high level tutorials on setting up a REST service using golang, focused on getting a go dev environment setup.

Setup

The first step to start rocking some go is to get it installed. Being a mac user, I initially installed go globally with brew, but then reverted to using gvm, as I love the flexibility I get with its node counterpart, nvm.

So now we have a local version of go installed, our GOPATH and PATH are setup, and we have access to the go executable. Now what? One of the neat things about gvm is the notion of pkgsets, basically allowing you to define separate "workspaces" and group a set of go projects using the same go version.

Let's create a pkgset called "work".

# Create the pkgset
$ gvm pkgset create work
# Set it as active, and the default choice
$ gvm pkgset use work --default

Sweet. Now, if we inspect our GOPATH and PATH, we can see that they have been updated to reflect our pkgset location. But what if we don't want to work in ~/.gvm/pkgsets/go1.4/work/? Let's setup a directory for our code, say ~/src/go.

# Or something else
$ mkdir -p ~/src/go/{bin,pkg,src}

Now that we have the proper folder structure for go, we'll need to update our environment. We could manually set GOPATH and PATH to be prefixed with our new src directory, but there's a better way. We'll use the gvm pkgenv command with our fresh work pkgset so that our new workspace will always be found in GOPATH.

Enter the following to pull open the environment variables for the work pkgset. We'll be changing the GOPATH and PATH variables to look at ~/src/go. Obviously, adjust your entries to reflect the directory structure on your machine.

Fin

That's the end of the introductory tutorial on building a REST service with golang. We've setup a proper go dev environment and have built a simple go program. Next we'll learn about using third party packages and setting up a basic webserver. Check it out.