Skip to content

Commit

Permalink
[WIP] Golang Boilerplate Service (#1)
Browse files Browse the repository at this point in the history
* Initial commit

* Initial Commit

* fix: remove wrong docker-compose file

* fix: fix broken import statement

* feat: use dep to manage dependencies

* fix: tidy import statement

* fix(docs): tidy up Readme.md

* feat: add circle.yml

* feat: add docker-compose file using timescaledb

* feat: use CircleCI 2.0 format

* fix: add blank test

* fix: add build step to Dockerfile

* fix: surround http.ListenAndServe with log.Fatal)

* fix: fix path issue in CircleCI config

* fix: run go get in circle build

* fix; use dep to install dependencies in CirlcleCI build

* fix: clarify readme.md
  • Loading branch information
Dara Hayes committed Feb 15, 2018
1 parent 81389a3 commit 0d90d34
Show file tree
Hide file tree
Showing 25 changed files with 528 additions and 2 deletions.
27 changes: 27 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Golang CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-go/ for more details
version: 2
jobs:
build:
docker:
# specify the version
- image: circleci/golang:1.9

# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
# - image: circleci/postgres:9.4

#### TEMPLATE_NOTE: go expects specific checkout path representing url
#### expecting it in the form of
#### /go/src/github.com/circleci/go-tool
#### /go/src/bitbucket.org/circleci/go-tool
working_directory: /go/src/github.com/aerogear/aerogear-metrics-api
steps:
- checkout
- run: go get github.com/mattn/goveralls
- run: go get -u github.com/golang/dep/cmd/dep
- run: dep ensure
- run: go test -v -cover -race -coverprofile=coverage.out
- run: /go/bin/goveralls -coverprofile=coverage.out -service=circle-ci -repotoken=$COVERALLS_TOKEN
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vendor/
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM golang:latest

RUN mkdir -p /aerogear-metrics-api

ADD . /aerogear-metrics-api

WORKDIR /aerogear-metrics-api

RUN go build aerogear_metrics_api.go

CMD ["./aerogear_metrics_api"]
27 changes: 27 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true


[[constraint]]
name = "github.com/darahayes/go-boom"
version = "1.0.1"

[[constraint]]
name = "github.com/gorilla/mux"
version = "1.6.1"

[prune]
go-tests = true
unused-packages = true
57 changes: 55 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,55 @@
# aerogear-metrics-service
AeroGear Mobile metrics service
# AeroGear Metrics API

**Please note this repo is a suggested implementation.** We have not agreed on implementing the service with Golang.

This is the server component of the AeroGear metrics service. It is a RESTful API that allows mobile clients to send metrics data which will get stored in a PostgreSQL database. The service is written in Golang.

## Prerequisites

* [Install Golang](https://golang.org/doc/install)
* [Install the dep package manager](https://golang.github.io/dep/docs/installation.html)
* [Install Docker and Docker Compose](https://docs.docker.com/compose/install/)

## Clone and Install Dependencies

First clone this repository to `$GOPATH/src/github.com/aerogear/aerogear-metrics-api`

Then run the following command to install the dependencies

```
dep ensure
```

## How to Run

Use `docker-compose` to start the PostgreSQL container:

```
docker-compose up
```

Now you can build and run the application locally with the following command:

```
go run cmd/aerogear-metrics-api.go
```

The default configuration will allow the application to connect to the PostgreSQL container.

### How to Build

To build an executable of the application simply run:

```
go build cmd/aerogear-metrics-api
```

This will produce a binary called `aerogear-metrics-api`

### Docker Build

Simply run the following:

```
docker build -t aerogear/aerogear-metrics-api .
```
26 changes: 26 additions & 0 deletions aerogear_metrics_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"log"
"net/http"

"github.com/aerogear/aerogear-metrics-api/pkg/handlers"
"github.com/aerogear/aerogear-metrics-api/pkg/metrics"
"github.com/aerogear/aerogear-metrics-api/pkg/web"
)

func main() {

app := metrics.NewApp(metrics.AppConfig{
DBConnectionString: "localhost", // refactor this into env var
})

h := handlers.BuildHandlers(app)

router := web.NewRouter(web.Config{
Routes: h.Routes,
})

port := ":3001"
log.Fatal(http.ListenAndServe(port, router))
}
10 changes: 10 additions & 0 deletions aerogear_metrics_api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package main

import (
"fmt"
"testing"
)

func BlankTest(t *testing.T) {
fmt.Println("done")
}
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
postgres:
image: timescale/timescaledb
ports:
- 5432:5432
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
PGDATA : /var/lib/postgresql/data/pgdata
volumes:
- psqlvolumes:/var/lib/postgresql/data/pgdata
45 changes: 45 additions & 0 deletions pkg/dao/dao.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package dao

import (
"errors"

"github.com/aerogear/aerogear-metrics-api/pkg/models"
)

type MetricsDAO struct {
DBConnectionString string
}

// Connect to database
func (m *MetricsDAO) Connect() {

}

// Create a metrics record
func (m *MetricsDAO) Create(metric models.Metric) (models.Metric, error) {
return metric, errors.New("Not Implemented yet")
}

// Update an existing job
// Not sure if we need this
func (m *MetricsDAO) Update() {

}

// Delete an existing job
// Not sure if we need this
func (m *MetricsDAO) Delete() {

}

// CheckConnection checks that we are connected to the database
// This will be used by the healthcheck
func (m *MetricsDAO) CheckConnection() {

}

func GetMetricsDAO(connectionString string) MetricsDAO {
return MetricsDAO{
DBConnectionString: connectionString,
}
}
36 changes: 36 additions & 0 deletions pkg/handlers/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package handlers

import (
"github.com/aerogear/aerogear-metrics-api/pkg/models"
"github.com/aerogear/aerogear-metrics-api/pkg/web"
)

var app models.App

type handlers struct {
Routes web.RouteList
}

func BuildHandlers(appInstance models.App) handlers {

app = appInstance

routes := web.RouteList{
web.Route{
Name: "Health Check",
Method: "GET",
Path: "/healthz",
Handler: healthz,
},
web.Route{
Name: "Create Metrics",
Method: "POST",
Path: "/metrics",
Handler: createMetric,
},
}

return handlers{
Routes: routes,
}
}
17 changes: 17 additions & 0 deletions pkg/handlers/healthzHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package handlers

import (
"net/http"
"time"

"github.com/aerogear/aerogear-metrics-api/pkg/models"
)

func healthz(w http.ResponseWriter, r *http.Request) {
status := models.Healthz{
Timestamp: time.Now().UTC(),
Status: "ok",
}

respondWithJSON(w, 200, status)
}
17 changes: 17 additions & 0 deletions pkg/handlers/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package handlers

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

func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(code)

err := json.NewEncoder(w).Encode(payload)

if err != nil {
panic(err)
}
}
32 changes: 32 additions & 0 deletions pkg/handlers/metricsHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package handlers

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

"github.com/aerogear/aerogear-metrics-api/pkg/models"
"github.com/darahayes/go-boom"
)

func createMetric(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()

var metric models.Metric

// decode the client payload into the metric var
if err := json.NewDecoder(r.Body).Decode(&metric); err != nil {
boom.BadRequest(w, "Invalid Data")
return
}

// create the record in the db
result, err := app.Metrics.Create(metric)

// handle errors
if err != nil {
boom.BadImplementation(w)
return
}

respondWithJSON(w, 200, result)
}
19 changes: 19 additions & 0 deletions pkg/metrics/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package metrics

import (
"github.com/aerogear/aerogear-metrics-api/pkg/dao"
"github.com/aerogear/aerogear-metrics-api/pkg/models"
)

func NewApp(config AppConfig) models.App {
mdao := dao.GetMetricsDAO(config.DBConnectionString)
mdao.Connect()
return models.App{
Metrics: Metrics{
mdao: mdao,
},
Health: Health{
mdao: mdao,
},
}
}
Loading

0 comments on commit 0d90d34

Please sign in to comment.