AJ ONeal
4 years ago
9 changed files with 205 additions and 0 deletions
@ -1,3 +1,14 @@ |
|||||
# goserv |
# goserv |
||||
|
|
||||
> Boilerplate for how I like to write a backend web service |
> Boilerplate for how I like to write a backend web service |
||||
|
|
||||
|
```bash |
||||
|
go mod tidy |
||||
|
go mod vendor |
||||
|
go generate -mod=vendor ./... |
||||
|
go build -mod=vendor . |
||||
|
``` |
||||
|
|
||||
|
```bash |
||||
|
./goserv run --listen :3000 --serve-path ./overrides |
||||
|
``` |
||||
|
@ -0,0 +1,4 @@ |
|||||
|
// +build !dev
|
||||
|
//go:generate go run -mod vendor github.com/shurcooL/vfsgen/cmd/vfsgendev -source="git.coolaj86.com/coolaj86/goserv/assets".Assets
|
||||
|
|
||||
|
package assets |
@ -0,0 +1,8 @@ |
|||||
|
// +build dev
|
||||
|
|
||||
|
package assets |
||||
|
|
||||
|
import "net/http" |
||||
|
|
||||
|
// Assets is the public file system which should be served by http
|
||||
|
var Assets http.FileSystem = http.Dir("../public") |
@ -0,0 +1,10 @@ |
|||||
|
module git.coolaj86.com/coolaj86/goserv |
||||
|
|
||||
|
go 1.15 |
||||
|
|
||||
|
require ( |
||||
|
github.com/go-chi/chi v4.1.2+incompatible |
||||
|
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect |
||||
|
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 |
||||
|
golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346 // indirect |
||||
|
) |
@ -0,0 +1,28 @@ |
|||||
|
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= |
||||
|
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= |
||||
|
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= |
||||
|
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= |
||||
|
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= |
||||
|
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= |
||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= |
||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= |
||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||
|
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/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= |
||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
||||
|
golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346 h1:hzJjkvxUIF3bSt+v8N5tBQNx/605vszZJ+3XsIamzZo= |
||||
|
golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= |
||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
@ -0,0 +1,131 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"compress/flate" |
||||
|
"flag" |
||||
|
"fmt" |
||||
|
"net/http" |
||||
|
"os" |
||||
|
|
||||
|
"git.coolaj86.com/coolaj86/goserv/assets" |
||||
|
"github.com/go-chi/chi" |
||||
|
"github.com/go-chi/chi/middleware" |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
name = "goserv" |
||||
|
version = "0.0.0" |
||||
|
date = "0001-01-01T00:00:00Z" |
||||
|
commit = "0000000" |
||||
|
) |
||||
|
|
||||
|
func usage() { |
||||
|
ver() |
||||
|
fmt.Println("") |
||||
|
fmt.Println("Use 'help <command>'") |
||||
|
fmt.Println(" help") |
||||
|
fmt.Println(" init") |
||||
|
fmt.Println(" run") |
||||
|
} |
||||
|
|
||||
|
func ver() { |
||||
|
fmt.Printf("%s v%s %s (%s)\n", name, version, commit[:7], date) |
||||
|
} |
||||
|
|
||||
|
type runOptions struct { |
||||
|
listen string |
||||
|
trustProxy bool |
||||
|
compress bool |
||||
|
static string |
||||
|
} |
||||
|
|
||||
|
var runFlags *flag.FlagSet |
||||
|
var runOpts runOptions |
||||
|
var initFlags *flag.FlagSet |
||||
|
|
||||
|
func init() { |
||||
|
runOpts = runOptions{} |
||||
|
runFlags = flag.NewFlagSet("run", flag.ExitOnError) |
||||
|
runFlags.StringVar(&runOpts.listen, "listen", ":3000", "the address and port on which to listen") |
||||
|
runFlags.BoolVar(&runOpts.trustProxy, "trust-proxy", false, "trust X-Forwarded-For header") |
||||
|
runFlags.BoolVar(&runOpts.compress, "compress", true, "enable compression for text,html,js,css,etc") |
||||
|
runFlags.StringVar(&runOpts.static, "serve-path", "", "path to serve, falls back to built-in web app") |
||||
|
} |
||||
|
|
||||
|
func main() { |
||||
|
args := os.Args[:] |
||||
|
if 1 == len(args) { |
||||
|
// "run" should be the default
|
||||
|
args = append(args, "run") |
||||
|
} |
||||
|
|
||||
|
if "help" == args[1] { |
||||
|
// top-level help
|
||||
|
if 2 == len(args) { |
||||
|
usage() |
||||
|
os.Exit(0) |
||||
|
return |
||||
|
} |
||||
|
// move help to subcommand argument
|
||||
|
self := args[0] |
||||
|
args = append([]string{self}, args[2:]...) |
||||
|
args = append(args, "--help") |
||||
|
} |
||||
|
|
||||
|
switch args[1] { |
||||
|
case "version": |
||||
|
ver() |
||||
|
os.Exit(0) |
||||
|
return |
||||
|
case "init": |
||||
|
initFlags.Parse(args[2:]) |
||||
|
case "run": |
||||
|
runFlags.Parse(args[2:]) |
||||
|
serve() |
||||
|
default: |
||||
|
usage() |
||||
|
os.Exit(1) |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func serve() { |
||||
|
r := chi.NewRouter() |
||||
|
|
||||
|
// A good base middleware stack
|
||||
|
if runOpts.trustProxy { |
||||
|
r.Use(middleware.RealIP) |
||||
|
} |
||||
|
if runOpts.compress { |
||||
|
r.Use(middleware.Compress(flate.DefaultCompression)) |
||||
|
} |
||||
|
r.Use(middleware.Logger) |
||||
|
r.Use(middleware.Recoverer) |
||||
|
|
||||
|
pub := http.FileServer(assets.Assets) |
||||
|
|
||||
|
var dev http.Handler |
||||
|
var devFS http.FileSystem |
||||
|
if len(runOpts.static) > 0 { |
||||
|
devFS = http.Dir(runOpts.static) |
||||
|
dev = http.FileServer(devFS) |
||||
|
r.Get("/*", func(w http.ResponseWriter, r *http.Request) { |
||||
|
if _, err := devFS.Open(r.URL.Path); nil != err { |
||||
|
pub.ServeHTTP(w, r) |
||||
|
return |
||||
|
} |
||||
|
dev.ServeHTTP(w, r) |
||||
|
}) |
||||
|
} else { |
||||
|
r.Get("/*", func(w http.ResponseWriter, r *http.Request) { |
||||
|
pub.ServeHTTP(w, r) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
fmt.Println("Listening for http on", runOpts.listen) |
||||
|
if err := http.ListenAndServe(runOpts.listen, r); nil != err { |
||||
|
fmt.Fprintf(os.Stderr, "%s", err) |
||||
|
os.Exit(1) |
||||
|
return |
||||
|
} |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
Hello, World! |
@ -0,0 +1,10 @@ |
|||||
|
// +build tools
|
||||
|
|
||||
|
// Package tools is a faux package for tracking dependencies that don't make it into the code
|
||||
|
package tools |
||||
|
|
||||
|
import ( |
||||
|
// these are 'go generate' tooling dependencies, not including in the binary
|
||||
|
_ "github.com/shurcooL/vfsgen" |
||||
|
_ "github.com/shurcooL/vfsgen/cmd/vfsgendev" |
||||
|
) |
Loading…
Reference in new issue