*Probably not production ready, but still pretty good.
dara.hayes@redhat.com
@darahayess
@darahayes
I think Node is not the best system to build a massive web server. I would use Go for that. And honestly, that’s the reason why I left Node. It was the realization that: oh, actually, this is not the best server-side system ever.
Ryan Dahl - Creator of Node.js
package main
import (
"io"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world!")
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":8000", nil)
}
What about?
So many frameworks
The built in net/http library is really good
But routing is hard
Gorilla Mux is our friend
net/http + gorilla/mux = $$$
also known as 'vendoring'
dep is the official experiment, but not yet the official tool
Deps are defined in Gopkg.toml and Gopkg.lock
$ dep init $ dep ensure -add github.com/user/library
.
├── Gopkg.lock
├── Gopkg.toml
├── README.md
├── cmd # Entry Points or executables in here
│ └── my-app
│ └── my-app.go
├── pkg # App modules/business logic stuff in here
│ ├── business
│ ├── config
│ ├── db
│ └── web
└── vendor # Dependencies are in here
HTTP Handlers
Business Logic
Database
type HelloWorldable interface {
Hello(string) (string, error)
}
HTTP handler(s) define interfaces
type HelloWorldService struct{}
func (hs *HelloWorldService) Hello(name string) (string, error) {
return "Hello world!", nil
}
Actual Implementations are separate
Use environment variables and fallback to sensible defaults
Personal Rule of Thumb:
The app should start (in local dev) with zero config
Testing Framework is built in!
Excellent HTTP Testing capabilities
Dependency Injection allows us to easily test components in isolation
Test files are normally kept in the same directory
Good Practice to separate integration tests and unit tests
Code Coverage reporting built in!
Not easy to aggregate coverage across multiple packages
(example shown later)
go test -cover -coverprofile=coverage.out
Upload to coveralls.io as part of CI using goveralls
Use Make for common build and test commands
$ make test
$ make test_integration
$ make build
$ make build_linux
$ make docker_build
$ make docker_release
...
FROM centos
ARG BINARY=./go-hello-server
EXPOSE 4000
COPY ${BINARY} /opt/go-hello-server
CMD "/opt/go-hello-server"
Build the binary first, then pass into the Docker image
Wait a minute...
That means our build environment is not guaranteed to be clean
This is a terrible idea.
The CI environment is guaranteed to be clean.
ONE super simple, low maintenance Dockerfile
Simplest developer workflow
Works in dev and in prod
Easiest way to build any version of the project, anytime.
Aim for simplicity, only complicate things if you really need to
Keeps custom build tooling to a minimum
Continuous Integration & Release
poorly documented black magic rituals
unnecessary amounts of setup & coordination
Let's make it ridiculously easy
(with CircleCI and goreleaser)
Goreleaser - CLI tool for managing Github releases
Define small single purpose, self contained CI jobs
- build - test - push - deploy
Create different workflows that use those jobs (based on conditions)
use git tags to kick off release process
(push button release/deploy)
okay... maybe it's not the *most* production ready server
(it's pretty good though)
- Handling JSON input
- Input Validation
- Logging
- Middleware Functions
- More
But these are really well documented online
Examples in github.com/aerogear/aerogear-app-metrics
end 🍕