Pokhara, NepalUTC+05:45 NPT
Open to conversations

Backend

A deliberately boring API

A small Go service with structured logs, graceful shutdown, health checks, and a container image under 20 MB.

2025
  • Go
  • PostgreSQL
  • Docker

Why build it

Most of my work is on the operational side of other people's services. I built this one to keep the other half sharp: a small Go API that does one thing, ships as a tiny image, and behaves predictably when it is killed.

It accepts a JSON payload, writes it to PostgreSQL, and returns a receipt. That is the whole product.

The parts that matter in production

The handlers are the easy part. The interesting decisions are around them:

  • Structured logs. Every request logs a request ID, method, path, status, and duration as JSON. No string concatenation, no guessing.
  • Graceful shutdown. On SIGTERM, the server stops accepting connections, waits for in-flight requests, then closes the database pool.
  • Health checks. /healthz is liveness. /readyz checks the database connection. They are separate because they answer different questions.
  • Timeouts everywhere. Server read and write timeouts, a database statement timeout, and a context deadline on every request.
srv := &http.Server{
    Addr:              cfg.Addr,
    Handler:           router,
    ReadHeaderTimeout: 5 * time.Second,
    ReadTimeout:       10 * time.Second,
    WriteTimeout:      15 * time.Second,
    IdleTimeout:       60 * time.Second,
}

The image

The build uses a multi-stage Dockerfile: compile with the Go toolchain, then copy the static binary into a distroless base. The result is under 20 MB and has no shell, which makes the attack surface smaller and the pull faster.

FROM golang:1.24 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/api ./cmd/api

FROM gcr.io/distroless/static-debian12
COPY --from=build /out/api /api
ENTRYPOINT ["/api"]

What "boring" buys

The service has no framework, no ORM, and no clever abstraction. It starts in milliseconds, exits cleanly, and logs enough to explain itself. When something goes wrong at 2 a.m., boring is a feature.