Note, this article is two years old and will be updated soon*

In this post we'll be looking at creating a really basic API in Go, and running it within Docker.

Folder structure:

api/Dockerfile api/server.go api/controllers/product_controller.go api/models/product.go api/models/database.go docker-compose.yml

Let's start with our docker-compose.yml

api: build: ./api ports: - 3000:3000 volumes: - ./api:/go/src/github.com/EwanValentine/project/api links: - database environment: - DB_NAME=project database: image: mongo:3.0 command: mongod --smallfiles --quiet --logpath=/dev/null

So here, we tell our Docker instance to find the Dockerfile in ./api, build it and configure some of our runtime settings. Such as mounting our project as a volume, so the container has access to the files. Exposing the port that our app's running on and linking our database container to our application container.

We're also calling in the default MongoDB container.

Now let's take a look at our API Dockerfile:

FROM golang:latest # Copy the local package files to the container’s workspace. ADD . /go/src/github.com/EwanValentine/project/api # Install our dependencies RUN go get github.com/go-martini/martini RUN go get github.com/martini-contrib/binding RUN go get github.com/martini-contrib/render RUN go get labix.org/v2/mgo RUN go get labix.org/v2/mgo/bson # Install api binary globally within container RUN go install github.com/EwanValentine/project/api # Set binary as entrypoint ENTRYPOINT /go/bin/api # Expose default port (3000) EXPOSE 3000

Now let's dive into the application code.

First up we have our server.go file. This will start the http server, configure our routes and assign the correct controller etc to each route.

package main import ( "github.com/EwanValentine/project/api/controllers" "github.com/EwanValentine/project/api/models" "github.com/go-martini/martini" "github.com/martini-contrib/binding" "github.com/martini-contrib/render" ) func main() { m := martini.Classic() m.Map(models.Database()) m.Use(render.Renderer()) pc := controllers.NewProductController(models.Database()) m.Get("/products", binding.Bind(models.Product{}), pc.GetAllProducts) m.Post("/products", binding.Bind(models.Product{}), pc.PostProduct) m.Run() }

What we're doing here is, calling the main function, which acts as an entrypoint to your application. Within that function, we're calling martini.Classic() which is our base web framework library.

Martini gives us some useful stuff, such as middlewares and routing etc.

We then set an instance of a controller, and pass its methods to two routes. Finally, we run m.Run() which starts our server.

Let's build out a model. But first, we need to create an instance of our Mongo database:

package models import ( "labix.org/v2/mgo" "os" ) func Database() *mgo.Session { session, err := mgo.Dial("project_database_1") if err != nil { panic(err) } session.SetMode(mgo.Monotonic, true) session.DB(os.Getenv("DB_NAME")) return session }

Here we call our MongoDB connection string ( project_database_1 is an alias of our database Docker container). Then we call our database name from the environment variable we have set within our docker-compose.yml. Finally, we return an instance of the MongoDB connection.

Now our model...

package models import ( "labix.org/v2/mgo/bson" ) type Product struct { Id bson.ObjectId `json:"id" bson:"_id"` Title string `form:"title" json:"title"` Description string `form:"description" json:"description"` Price float64 `form:"price" json:"price"` }

This is pretty straight forward. Using structs in Go, allows us to define strict data structure, this is especially handy when defining database structures.

Now to tie all of that together, let's add a controller:

package controllers import ( "github.com/EwanValentine/project/api/models" "github.com/martini-contrib/render" "labix.org/v2/mgo" "labix.org/v2/mgo/bson" "os" ) type ( ProductController struct { session *mgo.Session } ) func NewProductController(s *mgo.Session) *ProductController { return &ProductController{s} } func (pc *ProductController) GetAllProducts(r render.Render) { products := []models.Product{} session := pc.session.DB(os.Getenv("DB_NAME")).C("products") err := session.Find(nil).Limit(100).All(&products) if err != nil { panic(err) } r.JSON(200, products) } func (pc *ProductController) PostProduct(product models.Product, r render.Render) { session := pc.session.DB(os.Getenv("DB_NAME")).C("products") product.Id = bson.NewObjectId() product.Title = product.Title product.Description = product.Description product.Price = product.Price session.Insert(product) r.JSON(201, product) }

This is reasonably straight forward. We're defining a struct, injecting our database, creating a callable instance and injecting it into our controller's functions.