Bootstrap Practical Examples
A from-zero-to-one guide to building Bootstrap projects, covering common scenarios. All examples can be found as starting templates in the repository's _examples/ directory (quickstart / yaml_config / custom_builder / ddd).
1. A Minimal REST Service
1.1 config.yaml
app:
id: hello-service
name: hello-service
version: "1.0.0"
env: development
server:
http:
addr: ":8080"
middleware:
recovery:
stack_trace: true
cors:
allowed_origins: ["*"]
logging:
skip_paths: ["/health"]
logger:
type: zap
zap:
level: info
format: json
1.2 main.go
package main
import (
"fmt"
"log/slog"
"net/http"
"os"
bootstrap "github.com/tx7do/go-wind-bootstrap"
// Adapter submodules; builders self-register via blank imports.
_ "github.com/tx7do/go-wind-bootstrap/log/zap"
httpAdapter "github.com/tx7do/go-wind-bootstrap/transport/http"
)
func main() {
// --- Configure routes (must run before RunApp) ---
httpAdapter.RegisterServerSetup(func(srv *httpAdapter.Server) {
srv.GET("/", func(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintf(w, "Hello from go-wind-bootstrap quickstart!\n")
})
srv.GET("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
})
// --- One-line startup ---
if err := bootstrap.RunAppWithFlags(bootstrap.NewCommandFlags()); err != nil {
slog.Error("application exited with error", "error", err)
os.Exit(1)
}
}
go run main.go # Use the default config.yaml
go run main.go -c /path/to/config.yaml # Specify a configuration file
curl http://localhost:8080
RegisterServerSetup is append-style: routes generated by code generators and hand-written routes register independently without overwriting each other.
2. A gRPC Microservice
2.1 config.yaml
app:
name: user-service
server:
grpc:
addr: ":9000"
reflection: true
middleware:
recovery: {}
logging: {}
validate: {}
registry:
type: etcd
etcd:
endpoints: ["localhost:2379"]
ttl: 30
database:
sql:
driver: mysql
source: "user:pass@tcp(localhost:3306)/users?parseTime=true"
Once the service registry is configured, no registration code is needed: after the application starts (the AfterStart hook), it is registered automatically with real listening endpoints; at graceful shutdown (the BeforeStop hook), it is deregistered automatically before the servers stop.
2.2 main.go
package main
import (
"google.golang.org/grpc"
bootstrap "github.com/tx7do/go-wind-bootstrap"
_ "github.com/tx7do/go-wind-bootstrap/log/zap"
grpcAdapter "github.com/tx7do/go-wind-bootstrap/transport/grpc"
v1 "user-service/api/gen/v1"
)
func init() {
// Register the gRPC service implementation
grpcAdapter.RegisterServiceRegistrar(func(srv *grpc.Server) {
v1.RegisterUserServiceServer(srv, &userService{})
})
}
func main() {
if err := bootstrap.RunAppWithFlags(bootstrap.NewCommandFlags()); err != nil {
os.Exit(1)
}
}
3. The Full Declarative Bundle
One YAML file describes the cache, database, object storage, broker, service registry, and tracing at once; in semi-sealed mode, assembled instances are retrieved by type key after startup:
app:
name: order-service
server:
http:
addr: ":8080"
logger:
type: zap
zap:
level: info
writer: file
output_path: logs/app.log
max_size_mb: 100
max_backups: 10
registry:
type: consul
consul:
address: "localhost:8500"
tracer:
type: otlp
otlp:
endpoint: "localhost:4317"
insecure: true
cache:
redis:
addr: "localhost:6379"
key_prefix: "order"
database:
sql:
driver: postgres
source: "postgres://user:pass@localhost:5432/orders?sslmode=disable"
storage:
minio:
endpoint: "localhost:9000"
access_key: minioadmin
secret_key: minioadmin
use_ssl: false
broker:
kafka:
brokers: ["localhost:9092"]
bctx, err := bootstrap.BootstrapWithContext(nil, cfg)
if err != nil {
log.Fatal(err)
}
defer bctx.Cleanup()
// Retrieve assembled instances by type key
db := bctx.Database("gorm")
cache := bctx.Cache("redis")
oss := bctx.Storage("minio")
broker := bctx.Broker("kafka")
reg := bctx.Registry("consul") // GetService/Watch/Register/Deregister
fmt.Println(bctx.Config().GetApp().GetName())
fmt.Println(bctx.Config().GetServer().GetHttp().GetAddr())
bctx.App().Run(bctx)
4. Dockerfile
# multi-stage build
FROM golang:1.25-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /server ./cmd/server
FROM alpine:3.20
RUN apk add --no-cache ca-certificates tzdata
WORKDIR /app
COPY /server .
COPY configs/ ./configs/
EXPOSE 8080
CMD ["./server", "-c", "configs/config.yaml"]
5. Docker Compose
# docker-compose.yaml
services:
app:
build: .
ports:
- "8080:8080"
environment:
- DB_DSN=postgres://app:secret@postgres:5432/orders?sslmode=disable
depends_on:
- postgres
- redis
- etcd
postgres:
image: postgres:16
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
POSTGRES_DB: orders
ports:
- "5432:5432"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
etcd:
image: quay.io/coreos/etcd:v3.5.17
command: etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://etcd:2379
ports:
- "2379:2379"
