Boilerplate for how I like to write a backend web service.
Go to file
AJ ONeal 3d80901551 docs: update header gopher pilot image 2022-04-14 18:49:59 +00:00
assets add more CLI options and API scaffolding 2020-10-10 18:03:16 -06:00
examples add more CLI options and API scaffolding 2020-10-10 18:03:16 -06:00
internal add more CLI options and API scaffolding 2020-10-10 18:03:16 -06:00
public add more CLI options and API scaffolding 2020-10-10 18:03:16 -06:00
tools add more CLI options and API scaffolding 2020-10-10 18:03:16 -06:00
vendor update go-gitver 2020-10-12 15:29:25 -06:00
.gitignore add more CLI options and API scaffolding 2020-10-10 18:03:16 -06:00
.goreleaser.yml add more CLI options and API scaffolding 2020-10-10 18:03:16 -06:00
.ignore add more CLI options and API scaffolding 2020-10-10 18:03:16 -06:00
.prettierignore initial commit 2020-09-19 21:55:46 -06:00
.prettierrc initial commit 2020-09-19 21:55:46 -06:00
AUTHORS update LICENSE and AUTHORS 2020-09-28 21:17:10 -06:00
LICENSE initial commit 2020-09-19 21:55:46 -06:00
README.md docs: update header gopher pilot image 2022-04-14 18:49:59 +00:00
doc.go add more CLI options and API scaffolding 2020-10-10 18:03:16 -06:00
go.mod update go-gitver 2020-10-12 15:29:25 -06:00
go.sum update go-gitver 2020-10-12 15:29:25 -06:00
main.go remove extraneous version newline 2020-10-12 14:50:15 -06:00

README.md

GoServ

"golang gopher with goggles"

Boilerplate for how I like to write a backend web service

Build

Goreleaser

See https://webinstall.dev/goreleaser

Local-only

goreleaser --snapshot --skip-publish --rm-dist

Publish

# Get a token at https://github.com/settings/tokens
export GITHUB_TOKEN=xxxxxxx

# Remove --snapshot to error on non-clean releases
goreleaser --snapshot --rm-dist

The platform, publish URL, and token file can be changed in .goreleaser.yml:

env_files:
    gitea_token: ~/.config/goreleaser/gitea_token
gitea_urls:
    api: https://try.gitea.io/api/v1/

Manually

git clone ssh://gitea@git.coolaj86.com:22042/coolaj86/goserv.git ./goserv
pushd ./goserv
bash ./examples/build.sh
export GOFLAGS="-mod=vendor"
go mod tidy
go mod vendor
go generate -mod=vendor ./...
go build -mod=vendor -o dist/goserv .

To build for another platform (such as Raspberry Pi) set GOOS and GOARCH`:

GOOS=linux GOARCH=arm64 go build -mod=vendor -o dist/goserv-linux-arm64 .

Run

./dist/goserv run --listen :3000 --trust-proxy --serve-path ./overrides

Examples and Config Templates

The example files are located in ./examples

  • Caddyfile (web server config)
  • .env (environment variables)
  • build.sh
export BASE_URL=https://example.com

Authentication

You can use an OIDC provider or sign your own tokens.

go install -mod=vendor git.rootprojects.org/root/keypairs/cmd/keypairs

# Generate a keypair
keypairs gen -o key.jwk.json --pub pub.jwk.json

Create an Admin token:

# Sign an Admin token
echo '{ "sub": "random_ppid", "email": "me@example.com", "iss": "'"${BASE_URL}"'" }' \
    > admin.claims.json
keypairs sign --exp 1h ./key.jwk.json ./admin.claims.json > admin.jwt.txt 2> admin.jws.json

# verify the Admin token
keypairs verify ./pub.jwk.json ./admin.jwt.txt

Create a User token:

# Sign a User token
echo '{ "sub": "random_ppid", "email": "me@example.com", "iss": "'"${BASE_URL}"'" }' \
    > user.claims.json
keypairs sign --exp 1h ./key.jwk.json ./user.claims.json > user.jwt.txt 2> user.jws.json

# verify the User token
keypairs verify ./pub.jwk.json ./user.jwt.txt

Impersonation can be accomplished by appending the token sub (aka PPID) to the url as ?user_id=.

REST API

All routes require authentication, except for those at /api/public.

Authentication: Bearer <token>

Here's the API, in brief:

Base URL looks like https://example.com/api.

# Demo Mode Only
DELETE /public/reset                                    Drop database and re-initialize

# Public
GET  /public/ping                                       Health Check
POST /public/setup                  <= (none)           Bootstrap

# Admin-only
GET  /admin/ping                                        (authenticated) Health Check

# User
GET  /user/ping                                         (authenticated) Health Check

When you GET anything, it will be wrapped in the result.

Bootstrapping

The first user to hit the /api/setup endpoint will be the admin:

export TOKEN=$(cat admin.jwt.txt)
curl -X POST "${BASE_URL}/api/public/setup" -H "Authorization: Bearer ${TOKEN}"

Then the setup endpoint will be disabled:

curl -X POST "${BASE_URL}/api/public/setup" -H "Authorization: Bearer ${TOKEN}"

GoDoc

If the documentation is not public hosted you can view it with GoDoc:

godoc --http :6060

You can see abbreviated documentation with go's built-in doc, for example:

go doc git.example.com/example/goserv/internal/api

http://localhost:6060

Test

Create a test database. It must have test in the name.

DROP DATABASE "goserv_test"; CREATE DATABASE "goserv_test";

Run the tests:

export TEST_DATABASE_URL='postgres://postgres:postgres@localhost:5432/goserv_test'
go test -mod=vendor ./...

Dependencies

This setup can be run on a VPS, such as Digital Ocean, OVH, or Scaleway for $5/month with minimal dependencies:

  • VPS
  • Caddy
  • PostgreSQL
  • Serviceman

Mac, Linux:

curl -fsS https://webinstall.dev | bash
export PATH="$HOME:/.local/bin:$PATH"
webi caddy serviceman postgres

VPS Setup

You should have a domain pointing to a VPS and create a user account named app (because that's a common convention). This script will create an app user, copying the authorized_keys from the root account.

my_vps='example.com'
ssh root@"$my_vps" 'curl -sS https://webinstall.dev/ssh-adduser | bash'

You can then login as a normal user.

ssh app@"$my_vps"

It is now safe to disable the root account.

Caddy (Automatic HTTPS Server)

curl -fsS https://webinstall.dev/caddy | bash

You can start Caddy as a system service under the app user like this:

sudo setcap 'cap_net_bind_service=+ep' "$(readlink $(command -v caddy))"

sudo env PATH="$PATH" \
    serviceman add --name caddy --username app \
    caddy run --config ./Caddyfile

See the Cheat Sheets at https://webinstall.dev/caddy and https://webinstall.dev/serviceman

PostgreSQL (Database)

curl -fsS https://webinstall.dev/postgres | bash

You can start Postgres as a system service under the app user like this:

sudo env PATH="$PATH" \
    serviceman add --name postgres --username app -- \
    postgres -D /home/app/.local/share/postgres/var -p 5432

Username and password are set to 'postgres' by default:

psql 'postgres://postgres:postgres@localhost:5432/postgres'

See the Cheat Sheets at https://webinstall.dev/postgres and https://webinstall.dev/serviceman

Licenses

Copyright 2020 The GoServ Authors. All rights reserved.

Exceptions

These are probably also in the Public Domain.
(gathering the official data from any source would yield the same dataset)