Skilllibrary go-api-service
Guides Go HTTP API development: net/http handler patterns, middleware chaining (stdlib and chi/gorilla), context.Context propagation, structured error handling, graceful shutdown with signal trapping, dependency injection via struct receivers, database/sql connection pooling, JSON encoding/decoding, and httptest-based testing.
install
source · Clone the upstream repo
git clone https://github.com/merceralex397-collab/skilllibrary
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/merceralex397-collab/skilllibrary "$T" && mkdir -p ~/.claude/skills && cp -r "$T/09-backend-api-and-data/go-api-service" ~/.claude/skills/merceralex397-collab-skilllibrary-go-api-service && rm -rf "$T"
manifest:
09-backend-api-and-data/go-api-service/SKILL.mdsource content
Purpose
Guides the design and implementation of Go HTTP API services—from handler structure and middleware chaining through context propagation, structured error handling, graceful shutdown, dependency injection, and production deployment. Ensures Go-idiomatic patterns are used: explicit error returns (not panic),
http.Handler interface compliance, and proper context.Context threading.
When to use this skill
Use this skill when:
- building or modifying a Go HTTP API service (REST, gRPC-gateway, or JSON API)
- choosing between standard library
, chi, gorilla/mux, or other routersnet/http - implementing middleware (auth, logging, rate limiting, recovery)
- propagating
through handler → service → repository layerscontext.Context - configuring
connection pools or similar resourcesdatabase/sql - writing handler tests with
andhttptest.NewRequesthttptest.NewRecorder - implementing graceful shutdown for containerized deployments
- structuring a Go module for a service (cmd/, internal/, pkg/ layout)
Do not use this skill when
- the project is a CLI tool or library with no HTTP server component
- the task is about gRPC without an HTTP gateway—adapt or use a gRPC-specific skill
- the task is in a non-Go language—prefer
,flask
,express-node
, orfastapipython - the task is purely database schema design—prefer
orpostgresqldata-model
Operating procedure
- Define the service struct. Create a struct that holds all dependencies (logger, database, config). Attach handler methods to this struct so dependencies are available without globals.
- Choose a router. For simple services, use Go 1.22+ stdlib
with method-based routing. For path parameters and middleware groups, usehttp.ServeMux
orchi
. Document the choice.gorilla/mux - Wire middleware. Implement middleware as
. Chain in order: recovery → logging → auth → rate-limit → application handlers. Usefunc(http.Handler) http.Handler
or manual wrapping.chi.Chain - Propagate context. Accept
as the first parameter in all service and repository methods. Extract values fromcontext.Context
in handlers. User.Context()
for downstream calls.context.WithTimeout - Handle errors explicitly. Return
from all non-handler functions. In handlers, translate errors to HTTP status codes with a helper. Never useerror
for operational errors.panic - Implement JSON helpers. Create
andrespondJSON(w, status, data)
helpers to standardize encoding/decoding with properdecodeJSON(r, dst)
headers and error handling.Content-Type - Configure the database. Set
,db.SetMaxOpenConns()
, anddb.SetMaxIdleConns()
on thedb.SetConnMaxLifetime()
pool. Use*sql.DB
orsqlx
for convenience but understand the underlying pool.pgx - Implement graceful shutdown. Listen for
/SIGTERM
withSIGINT
. Callsignal.NotifyContext
with a timeout to drain in-flight requests.server.Shutdown(ctx) - Write tests. Use
+httptest.NewRequest
for unit tests. Usehttptest.NewRecorder
for integration tests. Runhttptest.NewServer
to catch race conditions.go test -race ./... - Verify production readiness. Run
,golangci-lint run
, andgo vet
. Confirm health/ready endpoints exist. Verify the binary builds withgo test -race
for containers.CGO_ENABLED=0
Decision rules
- Always return
from functions—never useerror
for control flow or expected failures.panic - Use
as the first parameter of every function that does I/O, calls downstream services, or may need cancellation.context.Context - Wrap errors with
to preserve the error chain forfmt.Errorf("operation: %w", err)
anderrors.Is
.errors.As - Use struct receivers for handlers to avoid global state. The service struct holds DB, logger, and config.
- Prefer
andhttp.Handler
interfaces over framework-specific types for portability.http.HandlerFunc - Set explicit timeouts on
(http.Server
,ReadTimeout
,WriteTimeout
).IdleTimeout - Use
withencoding/json.Decoder
for strict input parsing.DisallowUnknownFields() - Run
in CI—race conditions are common in concurrent Go code.go test -race ./... - Use
with a projectgolangci-lint
config for consistent linting..golangci.yml - Table-driven tests are the standard pattern for Go test organization.
Output requirements
— module layout, service struct, dependency wiringService Structure
— route registration, request parsing, response formatHandler Implementation
— error types, status mapping, error response shapeError Handling
— chain order, recovery, logging, authMiddleware
—Verification
commands,go test
, build checkgolangci-lint
References
Read these only when relevant:
— handler, middleware, shutdown, and service struct patternsreferences/implementation-patterns.md
— pre-deploy and pre-merge verification itemsreferences/validation-checklist.md
— common Go API runtime errors and their fixesreferences/failure-modes.md
Related skills
— OpenAPI specification and contract testingapi-contracts
— database integration and SQL patternspostgresql
— structured logging with slog or zerologobservability-logging
— rate limiting and retry strategiesrate-limits-retries
— data modeling and schema designdata-model
Anti-patterns
- Global
variable. Declaring a package-leveldb
instead of passing it through the service struct. Makes testing and connection management difficult.var db *sql.DB - Panic-driven error handling. Using
andpanic
as a control flow mechanism instead of returning errors. Reserverecover
for unexpected panics in middleware only.recover - Ignoring
. Passingcontext.Context
everywhere instead of threadingcontext.Background()
from the handler. This breaks cancellation and timeout propagation.r.Context() - Unbounded goroutines. Spawning goroutines in handlers without tracking or limiting them, leading to goroutine leaks under load.
- Writing after handler returns. Passing
to a goroutine that writes after the handler function returns, causing data races.http.ResponseWriter - Empty error checks. Writing
without wrapping or logging the error, losing all diagnostic context.if err != nil { return }
for dependency setup. Usinginit()
to create database connections or configure services, making testing and configuration switching impossible.func init()- JSON marshal without Content-Type. Calling
without settingjson.NewEncoder(w).Encode(data)
header first.Content-Type: application/json
Failure handling
- If a handler panics and the client sees a connection reset, add recovery middleware that catches panics, logs the stack, and returns 500.
- If context cancellation is not propagating, verify each layer accepts and passes
and that downstream calls usectx
(e.g.,ctx
).db.QueryContext(ctx, ...) - If the race detector reports failures, identify shared state accessed without synchronization and protect with mutex or redesign with channels.
- If connection pool exhaustion occurs, check
settings and ensure connections are returned (rows closed, transactions committed/rolled back).SetMaxOpenConns - If JSON decoding silently ignores fields, enable
on the decoder.DisallowUnknownFields() - If graceful shutdown kills in-flight requests, increase the shutdown timeout context or check that
(notShutdown
) is used.Close