transit¶
Shared HTTP & gRPC transport middleware for Go services — structured request logging, OpenTelemetry instrumentation, circuit breaking, rate limiting and client retry, from one framework-free module.
gitlab.com/phpboyscout/go/transit gives a service's HTTP and gRPC edges a single,
shared implementation of the cross-cutting transport concerns — the same logging,
tracing, circuit-breaking and rate-limiting behaviour whether the traffic arrives over
REST or gRPC, and whether the code is a server accepting calls or a client making them.
It is the middleware layer extracted from
go-tool-base.
Why¶
- Framework-free. It carries the gRPC SDK and the OpenTelemetry gRPC/HTTP contrib
instrumentation — that is the middleware's job — but nothing else. A
depfootprint_test.goguard forbids go-tool-base, Viper/Cobra, Charm and the cloud SDKs; the remaining dependencies aregolang.org/x/time/rate, go/redact andcockroachdb/errors. *slog.Loggerat the seam. Every middleware that logs takes a plain*slog.Logger, so nothing here pulls in a logging framework.- Server and client, both transports.
httpandgrpceach provide server handlers/interceptors and client round-trippers/interceptors, so a service and the clients it calls share one implementation of each concern. See the middleware model. - Resilience is one package. The circuit breaker and the keyed token-bucket
rate-limiter store live in
resilience; the HTTP and gRPC layers wrap them into transport-shaped middleware.
Where next¶
- Getting started — build a logged, traced, rate-limited server and a client that survives a flaky downstream, in about fifteen minutes.
- Compose HTTP middleware — server chains and client round-trippers (retry, circuit breaker, auth).
- Compose gRPC interceptors — server interceptor chains and client instrumentation.
- The middleware model — chain ordering, client vs server, and why the breaker sits outside retry.
- Reference — every config field, its default, and what happens when it is wrong.
- API reference — full godoc on pkg.go.dev.
What transit does not do¶
Worth knowing before you build on it:
- No distributed state. Every circuit breaker and rate limiter is per-process and in-memory. A limit of 50 rps across ten replicas admits 500.
- No configuration loading. Constructors take Go structs; decoding a config file onto them is your service's job.
- No
*http.Clientconstructor. transit ships transports, not connection policy — TLS, redirects and timeouts belong to the layer above. - No gRPC retry. The gRPC SDK already has it, via a service config policy.
- No metrics. Retries, rejections and breaker trips are not counted; callbacks are provided so you can count them.
The full list, with the reasoning for each, is in What transit does not do.
Part of the phpboyscout Go toolkit — small, framework-free Go modules extracted from go-tool-base.
Further reading¶
The blog carries a curated route through this subject: Building a web service in Go collects everything written about it, ordered so you can start at the beginning rather than newest-first.
Ask phpbotscout

He answers questions about the projects over on the Discord, citing the docs where they already cover it, and offering to raise an issue where they don't. Bring a bug, an idea, or a questionable engineering decision.