httputil

package module
v0.5.4 Latest Latest
Warning

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

Go to latest
Published: Dec 30, 2025 License: MIT Imports: 13 Imported by: 2

README

HTTP Utility Package

A lightweight Go package providing HTTP request/response utilities with:

  • Request context management
  • JSON encoding/decoding
  • Form data parsing
  • Data validation
  • DTO pattern implementation
  • Structured error handling with option pattern
  • Customizable error handlers
  • Validation middleware support

Features

Request Processing Pipeline
// Create context and handle request
r := httputil.Context(req, w)

// Decode, validate and convert to domain model
model, ok := httputil.DecodeAndValidateRequest(r, &requestDTO)
if !ok {
    return // Error already handled
}

// Encode response from domain model
_ = httputil.EncodeResponse(r, model, &responseDTO)
Form Data Parsing
// Parse form values into different types
err := r.DecodeForm("field", &target)
// Supports: string, int, bool, time.Time, slices, and custom types
Validation
// Validate request using schema
err := r.Validate(validator)

// Or get validation errors as map
errors, err := r.ValidateRequest(validator)
Option Pattern Configuration
// Custom error handler that logs errors
errorHandler := func(ctx httputil.RequestContext, err error) {
    log.Printf("Request error: %v", err)
    httputil.DefaultErrorHandler{}.HandleError(ctx, err)
}

// Use custom handler for a request
model, ok := httputil.DecodeAndValidateRequest(
    r, 
    &requestDTO,
    httputil.WithErrorHandler(errorHandler),
)

Installation

go get go.lumeweb.com/httputil

Error Handling

The package provides three levels of error handling:

  1. Automatic Errors (400/422/500 status codes):
// Errors automatically handled with appropriate status codes
model, ok := httputil.DecodeAndValidateRequest(r, &dto)
  1. Custom Error Handler:
// Create custom error handler
type LoggingHandler struct{}

func (h LoggingHandler) HandleError(ctx httputil.RequestContext, err error) {
    log.Printf("Error processing request: %v", err)
    httputil.DefaultErrorHandler{}.HandleError(ctx, err)
}

// Use custom handler
model, ok := httputil.DecodeAndValidateRequest(
    r,
    &dto,
    httputil.WithErrorHandler(LoggingHandler{}),
)
  1. Manual Error Handling:
// Full manual control
cfg := httputil.vdConfig{
    errorHandler: httputil.ErrorHandlerFunc(func(ctx httputil.RequestContext, err error) {
        // Custom error handling logic
    }),
}

model, ok := httputil.DecodeAndValidateRequest(r, &dto, httputil.WithErrorHandler(cfg.errorHandler))
Complete Example
Request/Response Flow
func createUserHandler(w http.ResponseWriter, req *http.Request) {
    // Initialize context
    r := httputil.Context(req, w)
    
    // Decode and validate request
    var createReq CreateUserRequest
    user, ok := httputil.DecodeAndValidateRequest(r, &createReq)
    if !ok {
        return // Error response already handled
    }
    
    // Business logic
    if err := userService.Create(user); err != nil {
        _ = r.Error(fmt.Errorf("creation failed: %w", err), http.StatusConflict)
        return
    }
    
    // Create and send response
    resp := UserResponse{}
    _ = httputil.EncodeResponse(r, user, &resp)
}
Custom Error Handling
type MetricsErrorHandler struct {
    metricsClient metrics.Client
}

func (h MetricsErrorHandler) HandleError(ctx httputil.RequestContext, err error) {
    // Track error metrics
    h.metricsClient.Increment("request.errors", 1)
    
    // Fallback to default handling
    httputil.DefaultErrorHandler{}.HandleError(ctx, err)
}

// Usage
func metricsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ctx := httputil.Context(r, w)
        handler := MetricsErrorHandler{metricsClient: globalMetrics}
        
        // Process request with metrics tracking
        var createReq CreateUserRequest
        user, ok := httputil.DecodeAndValidateRequest(
            ctx, 
            &createReq,
            httputil.WithErrorHandler(handler),
        )
        // ... rest of handler logic
    })
}

Error Handling

All errors are automatically formatted and returned with appropriate HTTP status codes.

Testing

The package includes comprehensive tests and mock implementations for easy testing.

Credits

Originally adapted from jape but extended with additional features.

Documentation

Overview

Package httputil provides HTTP utility functions for building robust web APIs in Go. It implements patterns for type-safe request/response handling with validation, structured error reporting, and OpenAPI documentation generation.

Key features: - DTO (Data Transfer Object) pattern for request/response marshaling - Declarative validation using struct schemas - Option pattern configuration for request processing - Automatic error classification and JSON error responses - Context-aware request handling - Integrated OpenAPI/Swagger documentation generation - TUS protocol support for file uploads - Route registration with built-in middleware support

The package emphasizes: - Type safety through generics - Clear separation of concerns - Customizable error handling - Consistent JSON formatting - Middleware-ready components - Self-documenting APIs

Router Features: - Unified route registration with access control - Automatic OpenAPI spec generation - Built-in support for common patterns:

  • Pagination (_start, _end params)
  • Sorting (_sort, _order params)
  • Filtering (custom field filters)
  • Global search (q param)

- Predefined Swagger definitions for:

  • Authenticated endpoints
  • Public endpoints
  • File uploads (multipart/form-data)
  • TUS protocol endpoints
  • Paginated responses

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DecodeAndValidateRequest added in v0.2.0

func DecodeAndValidateRequest[M any, D DTORequest[M]](
	r RequestContext,
	dto D,
	opts ...VDOption,
) (M, bool)

DecodeAndValidateRequest handles the complete request processing pipeline:

  1. Decode request body to DTO
  2. Validate using DTOValidator interface (if implemented)
  3. Convert to domain model using ToModel()

Returns:

  • The parsed domain model and true on success
  • Zero value and false on any error, with error handling delegated to the ErrorHandler

The function uses generics to ensure type safety and accepts optional VDOptions to customize processing behavior per invocation.

func EncodeResponse added in v0.2.0

func EncodeResponse[M any, D DTOResponse[M]](r RequestContext, model M, dto D, opts ...VDOption) error

EncodeResponse handles the response generation pipeline. It uses generics to ensure type safety when encoding the response.

func IsValidationError added in v0.2.0

func IsValidationError(err error) bool

IsValidationError checks if an error is or contains a ValidationError

func ToJSON added in v0.1.1

func ToJSON[T any](data T) ([]byte, error)

ToJSON is a generic helper function that marshals data to JSON. Provides consistent JSON encoding across the package.

Types

type DTORequest added in v0.1.1

type DTORequest[M any] interface {
	ToModel() (M, error) // Returns a new model of type M
}

DTORequest defines the interface for request Data Transfer Objects that convert HTTP requests to domain models. Implementations should: - Handle validation through the DTOValidator interface (optional) - Convert the raw request to a domain model - Return clean domain objects or validation errors

type DTOResponse added in v0.1.1

type DTOResponse[M any] interface {
	FromModel(model M) error // Takes a model of type M
}

DTOResponse defines the interface for response Data Transfer Objects that convert domain models to HTTP responses. Implementations should: - Format domain objects for JSON serialization - Maintain stable API contracts - Handle serialization-specific logic

type DTOValidator added in v0.1.1

type DTOValidator interface {
	Schema() *z.StructSchema
}

DTOValidator defines the validation interface for Data Transfer Objects. Implementations should return a zog schema that will be applied to validate incoming requests. The schema is used to: - Validate request structure - Provide meaningful error messages - Ensure data integrity before processing

type DefaultErrorHandler added in v0.3.0

type DefaultErrorHandler struct{}

DefaultErrorHandler provides standardized error handling with: - 400 Bad Request for JSON syntax/type errors - 422 Unprocessable Entity for validation errors - 500 Internal Server Error for all other cases

func (*DefaultErrorHandler) HandleError added in v0.3.0

func (h *DefaultErrorHandler) HandleError(ctx RequestContext, err error)

HandleError implements ErrorHandler with status code detection

type ErrorHandler added in v0.3.0

type ErrorHandler interface {
	HandleError(ctx RequestContext, err error)
}

ErrorHandler defines the strategy pattern for error handling during request processing. Implementations can customize error logging, formatting, and status code selection.

type FileUploadResult added in v0.5.2

type FileUploadResult struct {
	File     io.ReadSeekCloser
	Size     uint64
	Filename string
}

FileUploadResult contains the uploaded file and its metadata

type RequestContext

type RequestContext struct {
	echo.Context // Embed the Echo Context interface
}

RequestContext carries HTTP request-scoped values and provides utility methods for handling the complete request/response lifecycle. It combines: - Validation and encoding utilities - Embedded Echo Context for framework features

func Context

func Context(c echo.Context) RequestContext

Context creates a new RequestContext from an Echo context. This should be the primary way to initialize the request context for handlers.

func (RequestContext) Check

func (r RequestContext) Check(msg string, err error) error

Check simplifies error handling by: - Returning nil if err is nil - Wrapping the error with a message - Sending an HTTP 500 response if error exists

func (RequestContext) Decode

func (r RequestContext) Decode(v any) error

Decode reads and parses the request body as JSON into the provided value. Returns an error wrapped with type information if decoding fails

func (RequestContext) DecodeForm

func (r RequestContext) DecodeForm(key string, v any) error

DecodeForm parses and converts form values to various types. Supports: - Standard types (string, int, bool, time.Time) - Slice types from comma-separated values - Custom types implementing UnmarshalText or LoadString interfaces Panics if passed an unsupported type

func (RequestContext) Encode

func (r RequestContext) Encode(v any) error

Encode writes a JSON response to the client with consistent formatting: - Empty slices/maps render as []/{} instead of null - Uses indented JSON for human readability

func (RequestContext) Error

func (r RequestContext) Error(err error, status int) error

Error writes an HTTP error response and returns the error. Formats: - ValidationErrors as 422 Unprocessable Entity with field-specific errors - All other errors using Echo's error handler

func (RequestContext) PrepareFileUpload added in v0.5.2

func (r RequestContext) PrepareFileUpload(maxUploadSize int64) (*FileUploadResult, error)

PrepareFileUpload handles both multipart form uploads and raw body uploads. It supports: - Multipart form file uploads (with Content-Type: multipart/form-data) - Raw binary uploads (with any other Content-Type) - Automatic handling of seekable vs non-seekable sources - Size validation against maxUploadSize

func (RequestContext) Validate added in v0.1.1

func (r RequestContext) Validate(validator DTOValidator) error

Validate applies schema validation against a pre-populated DTOValidator. Returns: - nil on successful validation - ValidationError with field-specific errors on failure - Error wrapping original parse failure if schema validation cannot be performed

func (RequestContext) ValidateRequest added in v0.1.1

func (r RequestContext) ValidateRequest(entity DTOValidator) (map[string]string, error)

ValidateRequest performs validation and returns errors as a map of field->message. This is useful when you need to present validation errors in a structured format. Returns: - (nil, nil) if validation passes - (map, nil) with validation errors if validation fails - (nil, error) if there was a processing error

type VDOption added in v0.3.0

type VDOption func(*vdConfig)

VDOption configures DecodeAndValidateRequest processing behavior using the option pattern. These allow customizing validation handling per API endpoint while maintaining a consistent interface.

func WithErrorHandler added in v0.3.0

func WithErrorHandler(h ErrorHandler) VDOption

WithErrorHandler specifies a custom error handler for request processing. This option allows overriding the default error response strategy while maintaining the standard validation and decoding pipeline.

type ValidationError added in v0.2.0

type ValidationError struct {
	FieldErrors map[string]string // Field path -> error message
	// contains filtered or unexported fields
}

ValidationError represents structured validation failures with: - Field-specific error messages - Machine-readable error codes - Nested error support through error wrapping

func (*ValidationError) Error added in v0.2.0

func (v *ValidationError) Error() string

func (*ValidationError) Fields added in v0.2.0

func (v *ValidationError) Fields() map[string]string

Fields returns the field-specific error messages

func (*ValidationError) Unwrap added in v0.2.0

func (v *ValidationError) Unwrap() []error

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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