go-kit

module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: MIT

README

go-kit

A small, framework-agnostic Go module for infrastructure code shared by Porygon Labs services. It provides focused packages for configuration, outbound HTTP, structured logging, HTTP responses, opaque integer IDs, and OpenTelemetry tracing.

[!NOTE] This project is not affiliated with github.com/go-kit/kit.

[!IMPORTANT] The current release is pre-v1. Public interfaces may change while the module is hardened for production use. See the roadmap.

Purpose

go-kit exists to remove recurring service setup without becoming a web framework or a grab bag of generic helpers. A package belongs here only when the same stable behavior is needed by multiple services and can remain independent of their framework and domain.

Read Purpose and design for the admission criteria, design principles, trade-offs, and non-goals.

Packages

Package Use it for Dependencies
config Load an optional .env file and parse environment variables into a caller-defined struct caarlos0/env, godotenv
hash Encode positive int64 IDs as canonical, URL-safe Sqids sqids-go
httpclient Create validated Resty clients with optional safe retry policy go-resty/resty/v2
logger Configure and access a process-wide slog.Logger Standard library
response Write the shared { "meta", "data" } JSON response envelope Standard library
telemetry Initialize OTLP/gRPC tracing and create caller-named spans OpenTelemetry SDK

Import only the packages your application uses.

Requirements

The module currently declares Go 1.26.5 in go.mod. The supported Go-version policy is part of the high-priority roadmap.

Install

go get github.com/porygon-labs/go-kit@latest

Usage

Configuration
type Config struct {
    Port uint16 `env:"PORT" envDefault:"8080"`
    DSN  string `env:"DB_DSN,required,notEmpty"`
}

cfg, err := config.Load[Config]()
if err != nil {
    return err
}

Load reads .env from the current working directory when present. Existing process environment variables take precedence.

Outbound HTTP
client, err := httpclient.New(httpclient.Config{
    BaseURL: "https://orders.example.com/v1",
    Timeout: 3 * time.Second,
})
if err != nil {
    return err
}

var order Order
resp, err := client.R().
    SetContext(ctx).
    SetResult(&order).
    Get("/orders/42")
if err != nil {
    return err
}
if resp.IsError() {
    return fmt.Errorf("orders API returned %s", resp.Status())
}

Each call should use SetContext. HTTP error statuses are Resty responses, not Go errors. Retries are disabled by default; enable bounded retries with httpclient.WithRetry, which defaults to GET, HEAD, and OPTIONS only. Resty's internal logging is discarded so applications can redact and log returned errors at their own seam. See the HTTP client guide for retries, authentication, TLS, OTel, and testing.

Logging
logger.Init(logger.New("info", "json"))

logger.Info("server started", "port", 8080)
logger.Error("request failed", "error", err)

Call Init during startup. Before initialization, the package falls back to slog.Default().

HTTP responses
func handler(w http.ResponseWriter, _ *http.Request) {
    if err := response.OK(w, map[string]string{"hello": "world"}); err != nil {
        logger.Error("write response", "error", err)
    }
}

The response body is:

{"meta":{"is_success":true,"message":"OK"},"data":{"hello":"world"}}

The package accepts http.ResponseWriter, so it works directly with net/http and routers built on it. Other frameworks can pass their underlying response writer; go-kit does not depend on framework-specific types.

Opaque IDs
codec, err := hash.NewHash("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
if err != nil {
    return err
}

encoded, err := codec.Encode(42)
if err != nil {
    return err
}

ids, err := codec.Decode(encoded)
if err != nil {
    return err
}

[!WARNING] Sqids are obfuscation, not encryption or access control. Always authorize access to the decoded resource.

Tracing
shutdown, err := telemetry.Init(ctx, "orders-api", "otel-collector:4317")
if err != nil {
    return err
}
defer shutdown(context.Background())

ctx, end := telemetry.StartSpan(ctx)
defer end()

StartSpan derives the span name from its caller. The current Init implementation uses insecure gRPC transport; TLS and exporter options are a high-priority change.

Documentation

License

MIT — see LICENSE.

Directories

Path Synopsis
Package config loads application configuration from an optional .env file and process environment variables into a caller-defined struct.
Package config loads application configuration from an optional .env file and process environment variables into a caller-defined struct.
Package httpclient creates independently owned Resty clients for outbound HTTP calls.
Package httpclient creates independently owned Resty clients for outbound HTTP calls.
Package logger provides a single, globally-accessible slog.Logger.
Package logger provides a single, globally-accessible slog.Logger.
Package response provides a consistent JSON envelope for all API endpoints.
Package response provides a consistent JSON envelope for all API endpoints.
Package telemetry provides OpenTelemetry instrumentation helpers.
Package telemetry provides OpenTelemetry instrumentation helpers.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL