common

package module
v0.0.5 Latest Latest
Warning

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

Go to latest
Published: Apr 14, 2026 License: GPL-3.0 Imports: 13 Imported by: 0

README

go-common

CI Go Report Card Go Reference

A shared Go utility library for building HTTP APIs. Provides query parameter parsing, JSON request/response handling, structured logging, and request validation.

Installation

go get github.com/wispberry-tech/go-common
import common "github.com/wispberry-tech/go-common"

HTTP Utilities

Query Parameter Parsing

Parse query parameters with type safety and default values. All parsers return the default when the key is missing or the value is invalid.

// Integers
page := common.ParseQueryInt(r, "page", 1)           // ?page=3 → 3
id := common.ParseQueryInt64(r, "id", 0)              // ?id=9223372036854775807 → 9223372036854775807

// Floats
price := common.ParseQueryFloat64(r, "price", 0.0)    // ?price=19.99 → 19.99

// Booleans — accepts true/1/yes and false/0/no (case-insensitive)
active := common.ParseQueryBool(r, "active", false)    // ?active=yes → true

// Timestamps — expects RFC3339 format
since := common.ParseQueryTime(r, "since")             // ?since=2024-01-15T10:30:00Z → time.Time

// Optional strings — returns *string (nil when missing)
name := common.ParseQueryStringPtr(r, "name")          // ?name=alice → &"alice", missing → nil

// String slices — supports repeated keys
tags := common.ParseQueryStringSlice(r, "tag")         // ?tag=go&tag=rust → ["go", "rust"]
Pagination

Parse limit and offset query parameters with clamping.

// Reads ?limit=50&offset=10, clamps limit to [1, maxLimit], offset to >= 0
p := common.ParsePaginationParams(r, 20, 100) // defaultLimit=20, maxLimit=100
p.Limit  // 50
p.Offset // 10
JSON Responses

All responses are wrapped in a ResponseEnvelope with data, error, and meta fields.

// Success response — {"data": {"id": 1, "name": "alice"}}
common.WriteJSONResponse(w, http.StatusOK, user)

// Error response — {"error": {"code": "NOT_FOUND", "message": "User not found"}}
common.WriteJSONError(w, http.StatusNotFound, common.ErrCodeNotFound, "User not found", nil)

// Error with details — {"error": {"code": "VALIDATION_ERROR", "message": "...", "details": [...]}}
common.WriteJSONError(w, http.StatusBadRequest, common.ErrCodeValidationError, "Invalid input", details)
Error Code Constants

Pre-defined error codes for consistent API responses:

Constant Value
ErrCodeValidationError "VALIDATION_ERROR"
ErrCodeInvalidJSON "INVALID_JSON"
ErrCodeNotFound "NOT_FOUND"
ErrCodeUnauthorized "UNAUTHORIZED"
ErrCodeForbidden "FORBIDDEN"
ErrCodeInternalError "INTERNAL_ERROR"
Reading Request Bodies
var req CreateUserRequest
if err := common.ReadJSONBody(r, &req); err != nil {
    common.WriteJSONError(w, http.StatusBadRequest, common.ErrCodeInvalidJSON, "Invalid JSON body", nil)
    return
}

Logging

Structured, colorized logging built on charmbracelet/log.

Initialization

Call InitializeLogger once at startup. Options override defaults (info level, timestamps enabled, caller reporting enabled, 15:04:05 time format).

// Use defaults
common.InitializeLogger()

// Or customize with options
common.InitializeLogger(
    common.WithLevel("debug"),
    common.WithTimeFormat("2006-01-02 15:04:05"),
    common.WithCaller(false),
    common.WithTimestamp(true),
)
Log Messages

Structured logging with key-value pairs:

common.LogInfo("User logged in", "user_id", 123, "ip", "10.0.0.1")
common.LogError("Database error", "error", err, "query", "SELECT ...")
common.LogWarn("Rate limit approaching", "requests", 950, "limit", 1000)
common.LogDebug("Cache hit", "key", "user:123")

Formatted logging:

common.LogInfof("Processing %d items", count)
common.LogErrorf("Failed to connect to %s: %v", host, err)
common.LogWarnf("Retrying in %s", backoff)
common.LogDebugf("Query took %dms", elapsed)
Change Log Level at Runtime
common.SetLogLevel("debug") // "debug", "info", "warn", "error"

// Convenience toggles
common.EnableDebugLogging()
common.DisableDebugLogging()
Context-Aware Logging

Attach a logger to a context for request-scoped logging:

// Store logger in context
ctx := common.WithContext(r.Context(), logger)

// Retrieve later in the call chain
logger := common.FromContext(ctx)

Validation

Request validation using go-playground/validator, with automatic conversion of validation errors to API-friendly responses.

Basic Usage

Use the global Validate instance to validate structs with validate tags:

type CreateUserRequest struct {
    Email    string `json:"email" validate:"required,email"`
    Name     string `json:"name" validate:"required,min=2,max=100"`
    Password string `json:"password" validate:"required,min=8"`
}

if err := common.Validate.Struct(req); err != nil {
    resp := common.FormatValidationErrors(err)
    common.WriteJSONError(w, http.StatusBadRequest, common.ErrCodeValidationError, resp.Error, resp.Details)
    return
}

This produces a response like:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": [
      {"field": "email", "message": "email must be a valid email address", "value": "notanemail"},
      {"field": "password", "message": "password must be at least 8 characters long", "value": "short"}
    ]
  }
}
Custom Display Names with Struct Tags

Use the display struct tag to control how field names appear in error messages. Pass the struct to FormatValidationErrorsFor to enable tag lookup:

type CreateUserRequest struct {
    Email string `json:"email" validate:"required,email" display:"Email Address"`
    Age   int    `json:"age" validate:"required,gte=18" display:"Your Age"`
}

if err := common.Validate.Struct(req); err != nil {
    resp := common.FormatValidationErrorsFor(err, req) // pass the struct for display tag lookup
    // → "Email Address must be a valid email address"
    // → "Your Age must be greater than or equal to 18"
}

Without display tags, field names are derived by splitting camelCase (e.g., ClientUUID becomes Client UUID).

Supported Validation Tags

FormatValidationErrors generates human-readable messages for these validation tags:

Tag Message
required "{field} is required"
email "{field} must be a valid email address"
url "{field} must be a valid URL"
uuid "{field} must be a valid UUID"
min "{field} must be at least {param} characters long"
max "{field} must be no more than {param} characters long"
len "{field} must be exactly {param} characters long"
gt "{field} must be greater than {param}"
gte "{field} must be greater than or equal to {param}"
lt "{field} must be less than {param}"
lte "{field} must be less than or equal to {param}"
oneof "{field} must be one of: {param}"
numeric "{field} must be numeric"
alpha "{field} must contain only letters"
alphanum "{field} must contain only letters and numbers"
ip "{field} must be a valid IP address"
ipv4 "{field} must be a valid IPv4 address"
ipv6 "{field} must be a valid IPv6 address"
(other) "{field} is invalid"

Dependencies

License

GPL-3.0

Documentation

Overview

Package common provides reusable utilities for building HTTP APIs in Go. It includes helpers for query parameter parsing, JSON request/response handling, structured logging, and request validation.

The package is designed to reduce boilerplate in HTTP handlers and provide consistent error handling and logging across services.

Index

Constants

View Source
const (
	ErrCodeValidationError = "VALIDATION_ERROR"
	ErrCodeInvalidJSON     = "INVALID_JSON"
	ErrCodeNotFound        = "NOT_FOUND"
	ErrCodeUnauthorized    = "UNAUTHORIZED"
	ErrCodeForbidden       = "FORBIDDEN"
	ErrCodeInternalError   = "INTERNAL_ERROR"
)

Common error code constants for use with WriteJSONError.

Variables

Validate is the global validator instance with required struct validation enabled.

Functions

func DisableDebugLogging

func DisableDebugLogging()

DisableDebugLogging disables debug level logging (sets to info).

func EnableDebugLogging

func EnableDebugLogging()

EnableDebugLogging enables debug level logging.

func FromContext

func FromContext(ctx context.Context) *log.Logger

FromContext returns a logger from the context.

func InitializeLogger

func InitializeLogger(opts ...LoggerOption)

InitializeLogger configures the global charmbracelet/log logger for beautiful, colorized output with proper formatting. This should be called once at application startup. Options can be passed to override defaults.

func LogDebug

func LogDebug(msg interface{}, keyvals ...interface{})

LogDebug logs a debug message with optional key-value pairs.

func LogDebugf

func LogDebugf(format string, args ...interface{})

LogDebugf logs a formatted debug message.

func LogError

func LogError(msg interface{}, keyvals ...interface{})

LogError logs an error message with optional key-value pairs.

func LogErrorf

func LogErrorf(format string, args ...interface{})

LogErrorf logs a formatted error message.

func LogInfo

func LogInfo(msg interface{}, keyvals ...interface{})

LogInfo logs an info message with optional key-value pairs.

func LogInfof

func LogInfof(format string, args ...interface{})

LogInfof logs a formatted info message.

func LogWarn

func LogWarn(msg interface{}, keyvals ...interface{})

LogWarn logs a warning message with optional key-value pairs.

func LogWarnf

func LogWarnf(format string, args ...interface{})

LogWarnf logs a formatted warning message.

func ParseQueryBool

func ParseQueryBool(r *http.Request, key string, defaultValue bool) bool

ParseQueryBool extracts a boolean from query parameters. Accepts "true", "1", "yes" as true; "false", "0", "no" as false. Returns defaultValue if the key is missing or unrecognized.

func ParseQueryFloat64 added in v0.0.5

func ParseQueryFloat64(r *http.Request, key string, defaultValue float64) float64

ParseQueryFloat64 extracts a float64 from query parameters. Returns defaultValue if the key is missing or invalid.

func ParseQueryInt

func ParseQueryInt(r *http.Request, key string, defaultValue int) int

ParseQueryInt extracts an integer from query parameters. Returns defaultValue if the key is missing or invalid.

func ParseQueryInt64 added in v0.0.5

func ParseQueryInt64(r *http.Request, key string, defaultValue int64) int64

ParseQueryInt64 extracts an int64 from query parameters. Returns defaultValue if the key is missing or invalid.

func ParseQueryStringPtr

func ParseQueryStringPtr(r *http.Request, key string) *string

ParseQueryStringPtr extracts a string pointer from query parameters. Returns nil if the key is missing or empty.

func ParseQueryStringSlice added in v0.0.5

func ParseQueryStringSlice(r *http.Request, key string) []string

ParseQueryStringSlice extracts a string slice from query parameters. Supports repeated keys (e.g., ?tag=a&tag=b). Returns nil if the key is missing.

func ParseQueryTime

func ParseQueryTime(r *http.Request, key string) time.Time

ParseQueryTime extracts a time.Time from query parameters (RFC3339 format). Returns time.Time{} if the key is missing or invalid.

func Print

func Print(msg interface{}, keyvals ...interface{})

Print logs a message at info level.

func Printf

func Printf(format string, args ...interface{})

Printf logs a formatted message at info level.

func ReadJSONBody

func ReadJSONBody(r *http.Request, v any) error

ReadJSONBody decodes the JSON request body into the provided value.

func SetLogLevel

func SetLogLevel(level string)

SetLogLevel sets the global log level. Supports: debug, info, warn, error.

func WithContext

func WithContext(ctx context.Context, logger *log.Logger) context.Context

WithContext adds a logger to the context.

func WriteJSONError

func WriteJSONError(w http.ResponseWriter, statusCode int, code, message string, details any)

WriteJSONError writes a JSON error response with the given status code, error code, message, and optional details.

func WriteJSONResponse

func WriteJSONResponse(w http.ResponseWriter, statusCode int, data any)

WriteJSONResponse writes a JSON response with the given status code and data. The response is wrapped in a ResponseEnvelope.

Types

type ErrorBody

type ErrorBody struct {
	Code    string `json:"code"`
	Message string `json:"message"`
	Details any    `json:"details,omitempty"`
}

ErrorBody represents a structured error response.

type LoggerOption added in v0.0.5

type LoggerOption func(*loggerConfig)

LoggerOption configures the logger when passed to InitializeLogger.

func WithCaller added in v0.0.5

func WithCaller(enabled bool) LoggerOption

WithCaller enables or disables caller reporting in log output.

func WithLevel added in v0.0.5

func WithLevel(level string) LoggerOption

WithLevel sets the initial log level. Supports: "debug", "info", "warn", "error".

func WithTimeFormat added in v0.0.5

func WithTimeFormat(format string) LoggerOption

WithTimeFormat sets the time format string for log timestamps.

func WithTimestamp added in v0.0.5

func WithTimestamp(enabled bool) LoggerOption

WithTimestamp enables or disables timestamps in log output.

type PaginationParams added in v0.0.5

type PaginationParams struct {
	Limit  int
	Offset int
}

PaginationParams holds parsed pagination query parameters.

func ParsePaginationParams added in v0.0.5

func ParsePaginationParams(r *http.Request, defaultLimit, maxLimit int) PaginationParams

ParsePaginationParams extracts "limit" and "offset" from query parameters. Limit is clamped to [1, maxLimit]. Defaults: limit=defaultLimit, offset=0.

type ResponseEnvelope

type ResponseEnvelope struct {
	Data  any        `json:"data,omitempty"`
	Error *ErrorBody `json:"error,omitempty"`
	Meta  any        `json:"meta,omitempty"`
}

ResponseEnvelope wraps API responses in a consistent JSON structure. All responses include an optional Data, Error, and Meta field.

type ValidationError

type ValidationError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
	Value   string `json:"value,omitempty"`
}

ValidationError represents a single field validation error.

type ValidationErrorResponse

type ValidationErrorResponse struct {
	Error   string            `json:"error"`
	Details []ValidationError `json:"details"`
}

ValidationErrorResponse represents a structured response for validation errors.

func FormatValidationErrors

func FormatValidationErrors(err error) ValidationErrorResponse

FormatValidationErrors converts validator.ValidationErrors to user-friendly messages. Field display names are derived by splitting camelCase field names into words.

func FormatValidationErrorsFor added in v0.0.5

func FormatValidationErrorsFor(err error, v any) ValidationErrorResponse

FormatValidationErrorsFor converts validator.ValidationErrors to user-friendly messages, using the "display" struct tag from v for field display names when available.

type Request struct {
    Email string `validate:"required,email" display:"Email Address"`
}

Jump to

Keyboard shortcuts

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