Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vendor
18 changes: 18 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: build

on: [ push ]

jobs:
stagedbuild:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: stagedbuild
run: make stagedbuild

localbuild:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: localbuild
run: make localbuild
11 changes: 11 additions & 0 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: coverage

on: [ push ]

jobs:
cover:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: unit tests, with coverage
run: make checkcoverage
18 changes: 6 additions & 12 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Outputs, be they from test or from "make compile"
*.out

# Test binary, built with `go test -c`
*.test
# Dependency directories
vendor/

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# IDE files
.idea/*

# Dependency directories (remove the comment below to include it)
# vendor/
20 changes: 20 additions & 0 deletions CHANGEBLOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# CHANGEBLOG

This is a personal project, with no intent whatsoever on making any money out of it. The aim is to play
with [Fiber](https://gofiber.io/), as you've probably already guessed after checking the commit messages.

Why Fiber, you ask, and not something else? Well, I can't / won't write a microservice with several of them, so I had to pick.
Fiber I hadn't worked with hitherto. The first major bump I had was discovering Fiber v2 existed, after
having written all my code. Well, that might be ~100 lines, but still. Updating the dependencies isn't always fun.

Then I added the logger, and tried to play with `runtime.Callers`. Fun thing, depending on the `build` command, the logs
won't be the same - local path for a `make localbuild`, and something in `/go/src/github.com/floppyzedolfin/square/..`
for the `stagedbuild` command. I scraped that in the end, in order to only retrieve the calling function's name.

Oh, one fun thing I learnt as I was building my staged Dockerfile: building go without specifying `CGO_ENABLED=0` will
somehow leave C dependencies in the produced binary, when using the `net` package - which, obviously, is what I was
doing.
[This answer](https://stackoverflow.com/a/36308464/2106703) saved me countless hours of browsing the internet wondering
why running my microservice on centos would work, but it wouldn't on alpine or scratch.

For the sake of coverage, I've added an error case: when requesting the square of `0`, an error is returned.
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Section 1 - build the binary
FROM golang:1.15 as builder

WORKDIR /go/src/github.com/floppyzedolfin/square
COPY . /go/src/github.com/floppyzedolfin/square
# notice the .dockerignore prevented us from copying the vendors into the image
RUN make compile
RUN chmod +x /go/src/github.com/floppyzedolfin/square/build/square.out

# Section 2 - build the final image. All we need is the compiled binary
FROM scratch
COPY --from=builder /go/src/github.com/floppyzedolfin/square/build/square.out /app/square.out

ENTRYPOINT ["/app/square.out"]
29 changes: 29 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
NAME=square
VERSION=0.1
QUALITY_THRESHOLD=80

clean:
rm -f build/square.out
rm -f coverage.out
go clean -cache -testcache
docker rmi -f ${NAME}:${VERSION} || true

compile:
CGO_ENABLED=0 go build -o build/square.out cmd/main.go

localbuild: compile
docker build -t ${NAME}:${VERSION} build

run:
docker stop ${NAME} || true
docker run --rm -p 8530:3000 --name ${NAME} ${NAME}:${VERSION}

stagedbuild:
docker build -t ${NAME}:${VERSION} .

test:
go test ./...

checkcoverage:
go test ./... -coverprofile=coverage.out
go tool cover -func coverage.out | awk -F'\t' -v threshold=${QUALITY_THRESHOLD} '/^total:/{print $$0; overall_percent=$$NF; if (overall_percent >= threshold) {exit 0} else {exit 1}}'
74 changes: 73 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,74 @@
![](https://github.com/floppyzedolfin/square/workflows/build/badge.svg) ![](https://github.com/floppyzedolfin/square/workflows/coverage/badge.svg)

# square
Playing with Fiber

Playing with Fiber v2

This project was aimed at playing with Fiber. It builds a microservice, inside a Docker image, that exposes an endpoint
that squares an integer.

## Clone the repository

```bash
git clone https://github.com/floppyzedolfin/square.git
```

## Make targets

There are two options to build the image. Both options will generate the docker image, and should generate the same
docker image. Read below for potential differences.

### Compilation

- `make compile` compiles the service's binary locally. This includes GOPATH values, overwritten commands - such as `go`
, etc. It's useful for a dev point of view, as it provides an on-the-fly mechanism to build the current state of dev

### Docker image build

- `make localbuild` generates the image based on the deployed vendors, and on everything your environment has.
- `make stagedbuild` is a more generic build, as it happens inside a pristine environment. The overhead of this is that
we'll need to download the dependencies each time. This is the command to be used in CI for deliveries.

### Tests and coverage

- `make test` runs all the Unit Tests.
- `make checkcoverage` runs all the unit tests and ensures the coverage is at least 80%.

### Execution

- `make run` launches the service, exposing its port 3000 on the localhost's port 8530. The docker container will be
removed when stopped.

### Cleanup

- `make clean` removes local build and test caches, and removes the docker image

## Playing with it

Once you've ran `make run`, the service is up and running and you can shoot requests :

```bash
> curl -X POST -H "content-type:application/json" localhost:8530/square -d '{"value":4}'
{"value":16}
>
```

An error scenario has been built-in, for testing an example purposes, if the input value is `0`.

## Limitations

- So far, I haven't found a json parser that will cause invalid fields to raise an error. In our example here, the
following request is valid:

```json
{
"value": -4,
"foo": "bar"
}
```

## TODOs

- Refactor the `internal/*` files, I'm not sure I like the way they are
- Currently, the `square/build/Dockerfile` is an excerpt of the `square/Dockerfile`. I'd rather it wouldn't.

5 changes: 5 additions & 0 deletions build/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM scratch

COPY square.out /app/square.out

ENTRYPOINT ["/app/square.out"]
15 changes: 15 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import (
"github.com/floppyzedolfin/square/internal/server"
"github.com/floppyzedolfin/square/pkg/logger"
)

func main() {
// Create the server that will have all the necessary endpoints
s := server.NewServer()

const port = ":3000"
logger.Log(logger.Info, "starting server on port %s", port)
s.Listen(port)
}
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module github.com/floppyzedolfin/square

go 1.15

require (
github.com/gofiber/fiber/v2 v2.5.0
github.com/jinzhu/gorm v1.9.16
github.com/stretchr/testify v1.7.0
)
63 changes: 63 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/gofiber/fiber/v2 v2.5.0 h1:yml405Um7b98EeMjx63OjSFTATLmX985HPWFfNUPV0w=
github.com/gofiber/fiber/v2 v2.5.0/go.mod h1:f8BRRIMjMdRyt2qmJ/0Sea3j3rwwfufPrh9WNBRiVZ0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg=
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.18.0 h1:IV0DdMlatq9QO1Cr6wGJPVW1sV1Q8HvZXAIcjorylyM=
github.com/valyala/fasthttp v1.18.0/go.mod h1:jjraHZVbKOXftJfsOYoAjaeygpj5hr8ermTRJNroD7A=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201210223839-7e3030f88018 h1:XKi8B/gRBuTZN1vU9gFsLMm6zVz5FSCDzm8JYACnjy8=
golang.org/x/sys v0.0.0-20201210223839-7e3030f88018/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
28 changes: 28 additions & 0 deletions internal/server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package server

import (
"github.com/gofiber/fiber/v2"
)

// Server is the microservice application
type Server struct {
app *fiber.App
}

// NewServer returns a fully operational server, ready to Listen()
func NewServer() *Server {
s := Server{app: fiber.New()}
s.registerEndpoints()
return &s
}

// Listen starts the server on the associated port (which is a string starting with ':')
func (s *Server) Listen(port string) {
s.app.Listen(port)
}

// registerEndpoints adds all necessary endpoints to the server
// add each endpoint here
func (s *Server) registerEndpoints() {
s.registerSquare()
}
Loading