errenvelope

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Dec 23, 2025 License: MIT Imports: 10 Imported by: 0

README

err-envelope

Release Go Reference CI Go Report Card Sponsor

A tiny Go package for consistent HTTP error responses across services.

Why

Without a standard, every endpoint returns errors differently:

  • {"error": "bad request"}
  • {"message": "invalid email"}
  • {"code": "E123", "details": {...}}

This forces clients to handle each endpoint specially. err-envelope provides a single, predictable error shape.

What You Get

{
  "code": "VALIDATION_FAILED",
  "message": "Invalid input",
  "details": {
    "fields": {
      "email": "must be a valid email"
    }
  },
  "trace_id": "a1b2c3d4e5f6",
  "retryable": false
}

Every field has a purpose: stable codes for logic, messages for humans, details for context, trace IDs for debugging, and retry signals for resilience.

Rate limiting example:

{
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "trace_id": "a1b2c3d4e5f6",
  "retryable": true,
  "retry_after": "30s"
}

The retry_after field (human-readable duration) appears when WithRetryAfter() is used, alongside the standard Retry-After HTTP header.

Installation

go get github.com/blackwell-systems/err-envelope

Quick Start

package main

import (
    "net/http"
    errenvelope "github.com/blackwell-systems/err-envelope"
)

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
        email := r.URL.Query().Get("email")
        if email == "" {
            // Validation error with field details
            err := errenvelope.Validation(errenvelope.FieldErrors{
                "email": "is required",
            })
            errenvelope.Write(w, r, err)
            return
        }
        // ... success path
    })

    // Wrap with trace middleware
    http.ListenAndServe(":8080", errenvelope.TraceMiddleware(mux))
}
Response
$ curl http://localhost:8080/user
{
  "code": "VALIDATION_FAILED",
  "message": "Invalid input",
  "details": {
    "fields": {
      "email": "is required"
    }
  },
  "trace_id": "f8e7d6c5b4a39281",
  "retryable": false
}

API

Common Constructors
// Generic errors
errenvelope.Internal("Database connection failed")   // 500
errenvelope.BadRequest("Invalid JSON in body")       // 400

// Validation errors (400)
errenvelope.Validation(errenvelope.FieldErrors{
    "email": "invalid format",
    "age": "must be positive",
})

// Auth errors
errenvelope.Unauthorized("Missing token")             // 401
errenvelope.Forbidden("Insufficient permissions")     // 403

// Resource errors
errenvelope.NotFound("User not found")                // 404
errenvelope.MethodNotAllowed("POST not allowed")      // 405
errenvelope.RequestTimeout("Client timeout")          // 408
errenvelope.Conflict("Email already exists")          // 409
errenvelope.Gone("Resource permanently deleted")      // 410
errenvelope.PayloadTooLarge("Upload exceeds 10MB")    // 413
errenvelope.UnprocessableEntity("Invalid data format") // 422

// Infrastructure errors
errenvelope.RateLimited("Too many requests")          // 429
errenvelope.Unavailable("Service temporarily down")   // 503
errenvelope.Timeout("Database query timed out")       // 504

// Downstream errors
errenvelope.Downstream("payments", err)               // 502
errenvelope.DownstreamTimeout("payments", err)        // 504
Formatted Constructors

Use fmt.Printf-style formatting for dynamic error messages:

// Low-level formatted constructors
userID := "12345"
err := errenvelope.Newf(CodeNotFound, 404, "user %s not found", userID)

// Wrap errors with formatting
dbErr := sql.ErrNoRows
err := errenvelope.Wrapf(CodeInternal, 500, "failed to fetch user %s", dbErr, userID)

// Formatted helper functions
errenvelope.Internalf("database %s connection failed", "postgres")
errenvelope.NotFoundf("user %d not found", 12345)
errenvelope.BadRequestf("invalid field: %s", fieldName)
errenvelope.Unauthorizedf("missing header: %s", "Authorization")
errenvelope.Forbiddenf("insufficient permissions for %s", resource)
errenvelope.Conflictf("email %s already exists", email)
errenvelope.Timeoutf("query exceeded %dms timeout", 5000)
errenvelope.Unavailablef("service %s is down", "payments")
Custom Errors
// Low-level constructor
err := errenvelope.New(
    errenvelope.CodeInternal,
    http.StatusInternalServerError,
    "Database connection failed",
)

// Add details
err = err.WithDetails(map[string]any{
    "database": "postgres",
    "host": "db.example.com",
})

// Add trace ID
err = err.WithTraceID("abc123")

// Override retryable
err = err.WithRetryable(true)

// Set retry-after duration (for rate limiting, unavailable, etc.)
err = err.WithRetryAfter(60 * time.Second)
Writing Responses
// Write error response
errenvelope.Write(w, r, err)

// Automatically handles:
// - Sets Content-Type: application/json
// - Sets X-Request-Id header (if trace ID present)
// - Sets Retry-After header (if retry duration present)
// - Sets correct HTTP status
// - Encodes error as JSON

Headers set automatically:

  • X-Request-Id: Trace ID for log correlation (if present)
  • Retry-After: Duration in seconds for retryable errors (if specified via WithRetryAfter())
Mapping Arbitrary Errors
// Convert any error to envelope
err := someLibrary.DoSomething()
errenvelope.Write(w, r, err)  // From() called automatically

// Handles:
// - context.DeadlineExceeded → Timeout
// - context.Canceled → Canceled (499)
// - net.Error with Timeout() → Timeout
// - *errenvelope.Error → passthrough
// - Unknown errors → Internal (500)
Trace ID Middleware
mux := http.NewServeMux()
// ... register handlers

// Wrap with trace middleware
handler := errenvelope.TraceMiddleware(mux)
http.ListenAndServe(":8080", handler)

// Generates trace ID if missing
// Propagates X-Request-Id header
// Adds to context for downstream access
Structured Logging (slog)

Errors implement slog.LogValuer for seamless structured logging integration (Go 1.21+):

import "log/slog"

err := Internal("database connection failed").
    WithTraceID("abc123").
    WithDetails(map[string]string{"database": "postgres"})

// Log with slog - all error fields included automatically
slog.Info("request failed", "error", err)
// Output: {"level":"INFO","msg":"request failed","error":{"code":"INTERNAL","message":"database connection failed","status":500,"retryable":false,"trace_id":"abc123","details":{"database":"postgres"}}}

// Works with structured logging context
slog.Error("processing error",
    "error", err,
    "user_id", 123,
    "path", r.URL.Path)

The LogValue() method automatically includes: code, message, status, retryable, trace_id, details, retry_after, and cause.

Error Codes

Code HTTP Status Retryable Use Case
INTERNAL 500 No Unexpected server errors
BAD_REQUEST 400 No Malformed requests
VALIDATION_FAILED 400 No Invalid input data
UNAUTHORIZED 401 No Missing/invalid auth
FORBIDDEN 403 No Insufficient permissions
NOT_FOUND 404 No Resource doesn't exist
METHOD_NOT_ALLOWED 405 No Invalid HTTP method
REQUEST_TIMEOUT 408 Yes Client timeout
CONFLICT 409 No State conflict (duplicate)
GONE 410 No Resource permanently deleted
PAYLOAD_TOO_LARGE 413 No Request body too large
UNPROCESSABLE_ENTITY 422 No Semantic validation failed
RATE_LIMITED 429 Yes Too many requests
CANCELED 499 No Client canceled request
UNAVAILABLE 503 Yes Service temporarily down
TIMEOUT 504 Yes Gateway timeout
DOWNSTREAM_ERROR 502 Yes Upstream service failed
DOWNSTREAM_TIMEOUT 504 Yes Upstream service timeout

Design Principles

Minimal: ~300 lines, stdlib only, single responsibility.

Framework-Agnostic: Works with net/http out of the box. Easy adapters for chi/gin/echo.

Predictable: Error codes are stable (never change). Messages may evolve for clarity. Sensible defaults for status codes and retryability.

Observable: Trace IDs for request correlation. Structured details for logging. Cause chains preserved via errors.Unwrap.

Compatibility

If you already use Problem Details (RFC 9457), this can coexist—map between formats at the edge.

JSON Schema

A JSON Schema is included for client tooling and contract testing:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "errenvelope.Error",
  "required": ["code", "message", "retryable"],
  "properties": {
    "code": { "type": "string" },
    "message": { "type": "string" },
    "details": { "type": "object" },
    "trace_id": { "type": "string" },
    "retryable": { "type": "boolean" },
    "retry_after": { "type": "string" }
  }
}

Use this to validate responses, generate TypeScript types, or document your API.

Examples

See examples/nethttp for a complete demo server.

Run it:

cd examples/nethttp
go run main.go

Test endpoints:

curl http://localhost:8080/validate
curl http://localhost:8080/user/
curl http://localhost:8080/downstream
curl http://localhost:8080/protected
curl http://localhost:8080/timeout

Integration Patterns

net/http (default)
mux := http.NewServeMux()

mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
    if err := validate(r); err != nil {
        errenvelope.Write(w, r, err)
        return
    }

    // ... success path
    w.WriteHeader(http.StatusOK)
})

_ = http.ListenAndServe(":8080", errenvelope.TraceMiddleware(mux))
Chi

Chi is net/http-native, so you can use errenvelope.TraceMiddleware directly. The adapter exists for convenience and readability.

import (
    errchi "github.com/blackwell-systems/err-envelope/integrations/chi"
    "github.com/go-chi/chi/v5"
)

r := chi.NewRouter()
r.Use(errchi.Trace)

r.Get("/user", func(w http.ResponseWriter, r *http.Request) {
    errenvelope.Write(w, r, errenvelope.NotFound("User not found"))
})
Gin
import (
    errgin "github.com/blackwell-systems/err-envelope/integrations/gin"
    "github.com/gin-gonic/gin"
)

r := gin.Default()
r.Use(errgin.Trace())

r.GET("/user", func(c *gin.Context) {
    errgin.Write(c, errenvelope.Unauthorized("Missing token"))
})
Echo
import (
    errecho "github.com/blackwell-systems/err-envelope/integrations/echo"
    "github.com/labstack/echo/v4"
)

e := echo.New()
e.Use(errecho.Trace)

e.GET("/user", func(c echo.Context) error {
    return errecho.Write(c, errenvelope.BadRequest("Invalid request"))
})
OpenAPI / TypeScript

Use the included JSON Schema to:

  • Validate error contracts in CI
  • Generate client types
  • Document a shared error response model across services

Versioning

Follows semantic versioning. No breaking changes to envelope fields (code, message, details, trace_id, retryable) in minor releases.

Used By

License

MIT

Contributing

This is a reference implementation. Fork and adapt to your needs.

If you find a bug or have a suggestion, open an issue.

Documentation

Overview

Package errenvelope provides a tiny, framework-agnostic server-side HTTP error envelope for Go services. It standardizes code/message/details/trace_id/retryable and includes helpers for validation, auth, timeouts, and downstream errors.

Index

Examples

Constants

View Source
const (
	// HeaderTraceID is the standard header name for trace/request IDs.
	HeaderTraceID = "X-Request-Id"
)

Variables

This section is empty.

Functions

func Is

func Is(err error, code Code) bool

Is checks if an error has the given code.

func TraceIDFromRequest

func TraceIDFromRequest(r *http.Request) string

TraceIDFromRequest extracts the trace ID from the request header or context.

func TraceMiddleware

func TraceMiddleware(next http.Handler) http.Handler

TraceMiddleware generates or propagates a trace ID for each request.

Example

ExampleTraceMiddleware demonstrates adding trace ID middleware.

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	errenvelope "github.com/blackwell-systems/err-envelope"
)

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/api/user", func(w http.ResponseWriter, r *http.Request) {
		// Trace ID is available from request
		traceID := errenvelope.TraceIDFromRequest(r)
		fmt.Printf("Trace ID present: %v\n", traceID != "")

		w.WriteHeader(http.StatusOK)
	})

	// Wrap with trace middleware
	handler := errenvelope.TraceMiddleware(mux)

	req := httptest.NewRequest("GET", "/api/user", nil)
	w := httptest.NewRecorder()
	handler.ServeHTTP(w, req)

}
Output:

Trace ID present: true

func WithTraceID

func WithTraceID(ctx context.Context, id string) context.Context

WithTraceID adds a trace ID to the context.

func Write

func Write(w http.ResponseWriter, r *http.Request, err error)

Write writes a consistent JSON error envelope to the response. If TraceID is missing on the error, it tries to derive it from the request.

Example (Conflict)

ExampleWrite_conflict demonstrates handling conflict errors (e.g., duplicate resources).

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	errenvelope "github.com/blackwell-systems/err-envelope"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Simulate duplicate email
		err := errenvelope.Conflict("User with this email already exists")
		errenvelope.Write(w, r, err)
	})

	req := httptest.NewRequest("POST", "/signup", nil)
	w := httptest.NewRecorder()
	handler(w, req)

	fmt.Printf("Status: %d\n", w.Code)
}
Output:

Status: 409
Example (Downstream)

ExampleWrite_downstream demonstrates handling downstream service errors.

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	errenvelope "github.com/blackwell-systems/err-envelope"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Simulate payment service failure
		paymentErr := fmt.Errorf("connection refused")
		err := errenvelope.Downstream("payment-service", paymentErr)
		errenvelope.Write(w, r, err)
	})

	req := httptest.NewRequest("POST", "/checkout", nil)
	w := httptest.NewRecorder()
	handler(w, req)

	fmt.Printf("Status: %d\n", w.Code)
}
Output:

Status: 502
Example (NotFound)

ExampleWrite_notFound demonstrates handling 404 errors.

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	errenvelope "github.com/blackwell-systems/err-envelope"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Simulate user not found
		err := errenvelope.NotFound("User not found")
		errenvelope.Write(w, r, err)
	})

	req := httptest.NewRequest("GET", "/users/999", nil)
	w := httptest.NewRecorder()
	handler(w, req)

	fmt.Printf("Status: %d\n", w.Code)
}
Output:

Status: 404
Example (Unauthorized)

ExampleWrite_unauthorized demonstrates handling authentication errors.

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	errenvelope "github.com/blackwell-systems/err-envelope"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		token := r.Header.Get("Authorization")
		if token == "" {
			err := errenvelope.Unauthorized("Missing authorization token")
			errenvelope.Write(w, r, err)
			return
		}

		w.WriteHeader(http.StatusOK)
	})

	req := httptest.NewRequest("GET", "/protected", nil)
	w := httptest.NewRecorder()
	handler(w, req)

	fmt.Printf("Status: %d\n", w.Code)
}
Output:

Status: 401
Example (Validation)

ExampleWrite_validation demonstrates handling validation errors with field details.

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	errenvelope "github.com/blackwell-systems/err-envelope"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		email := r.URL.Query().Get("email")
		password := r.URL.Query().Get("password")

		if email == "" || password == "" {
			err := errenvelope.Validation(errenvelope.FieldErrors{
				"email":    "is required",
				"password": "is required",
			})
			errenvelope.Write(w, r, err)
			return
		}

		w.WriteHeader(http.StatusOK)
	})

	req := httptest.NewRequest("GET", "/signup", nil)
	w := httptest.NewRecorder()
	handler(w, req)

	fmt.Printf("Status: %d\n", w.Code)
	fmt.Printf("Content-Type: %s\n", w.Header().Get("Content-Type"))
}
Output:

Status: 400
Content-Type: application/json

Types

type Code

type Code string

Code is a stable, machine-readable error identifier.

const (
	// Generic
	CodeInternal         Code = "INTERNAL"
	CodeBadRequest       Code = "BAD_REQUEST"
	CodeNotFound         Code = "NOT_FOUND"
	CodeMethodNotAllowed Code = "METHOD_NOT_ALLOWED"
	CodeGone             Code = "GONE"
	CodeConflict         Code = "CONFLICT"
	CodePayloadTooLarge  Code = "PAYLOAD_TOO_LARGE"
	CodeRequestTimeout   Code = "REQUEST_TIMEOUT"
	CodeRateLimited      Code = "RATE_LIMITED"
	CodeUnavailable      Code = "UNAVAILABLE"

	// Validation / auth
	CodeValidationFailed    Code = "VALIDATION_FAILED"
	CodeUnauthorized        Code = "UNAUTHORIZED"
	CodeForbidden           Code = "FORBIDDEN"
	CodeUnprocessableEntity Code = "UNPROCESSABLE_ENTITY"

	// Timeouts / cancellations
	CodeTimeout  Code = "TIMEOUT"
	CodeCanceled Code = "CANCELED"

	// Downstream
	CodeDownstream        Code = "DOWNSTREAM_ERROR"
	CodeDownstreamTimeout Code = "DOWNSTREAM_TIMEOUT"
)

type Error

type Error struct {
	Code      Code   `json:"code"`
	Message   string `json:"message"`
	Details   any    `json:"details,omitempty"`
	TraceID   string `json:"trace_id,omitempty"`
	Retryable bool   `json:"retryable"`

	// Not serialized:
	Status     int           `json:"-"`
	Cause      error         `json:"-"`
	RetryAfter time.Duration `json:"-"` // Duration to wait before retrying
}

Error is a structured error envelope for HTTP APIs.

func BadRequest

func BadRequest(msg string) *Error

BadRequest creates a generic bad request error (400).

func BadRequestf added in v1.1.0

func BadRequestf(format string, args ...any) *Error

BadRequestf creates a generic bad request error (400) with a formatted message.

func Conflict

func Conflict(msg string) *Error

Conflict creates a conflict error (409).

func Conflictf added in v1.1.0

func Conflictf(format string, args ...any) *Error

Conflictf creates a conflict error (409) with a formatted message.

func Downstream

func Downstream(service string, cause error) *Error

Downstream creates an error for downstream service failures (502).

func DownstreamTimeout

func DownstreamTimeout(service string, cause error) *Error

DownstreamTimeout creates a timeout error for downstream services (504).

func Forbidden

func Forbidden(msg string) *Error

Forbidden creates a forbidden error (403).

func Forbiddenf added in v1.1.0

func Forbiddenf(format string, args ...any) *Error

Forbiddenf creates a forbidden error (403) with a formatted message.

func From

func From(err error) *Error

From maps arbitrary errors into an *Error. Handles context errors, network timeouts, and wraps unknown errors.

Example

ExampleFrom demonstrates mapping arbitrary errors to envelopes.

package main

import (
	"fmt"

	errenvelope "github.com/blackwell-systems/err-envelope"
)

func main() {
	// Standard library error
	err := fmt.Errorf("something went wrong")
	envelope := errenvelope.From(err)

	fmt.Printf("Code: %s\n", envelope.Code)
	fmt.Printf("Status: %d\n", envelope.Status)
}
Output:

Code: INTERNAL
Status: 500

func Gone

func Gone(msg string) *Error

Gone creates a gone error (410) for resources that no longer exist.

func Internal

func Internal(msg string) *Error

Internal creates an internal server error (500).

func Internalf added in v1.1.0

func Internalf(format string, args ...any) *Error

Internalf creates an internal server error (500) with a formatted message.

func MethodNotAllowed

func MethodNotAllowed(msg string) *Error

MethodNotAllowed creates a method not allowed error (405).

func New

func New(code Code, status int, msg string) *Error

New creates a new Error with the given code, HTTP status, and message. If status is 0, defaults to 500. If message is empty, uses a default.

Example

ExampleNew demonstrates creating a custom error with details.

package main

import (
	"fmt"
	"net/http"

	errenvelope "github.com/blackwell-systems/err-envelope"
)

func main() {
	err := errenvelope.New(
		errenvelope.CodeInternal,
		http.StatusInternalServerError,
		"Database connection failed",
	)

	err = err.WithDetails(map[string]any{
		"database": "postgres",
		"host":     "db.example.com",
	})

	err = err.WithRetryable(true)

	fmt.Printf("Code: %s\n", err.Code)
	fmt.Printf("Message: %s\n", err.Message)
	fmt.Printf("Retryable: %v\n", err.Retryable)
}
Output:

Code: INTERNAL
Message: Database connection failed
Retryable: true

func Newf added in v1.1.0

func Newf(code Code, status int, format string, args ...any) *Error

Newf creates a new Error with a formatted message. Mirrors fmt.Errorf ergonomics for creating errors with interpolated values.

func NotFound

func NotFound(msg string) *Error

NotFound creates a not found error (404).

func NotFoundf added in v1.1.0

func NotFoundf(format string, args ...any) *Error

NotFoundf creates a not found error (404) with a formatted message.

func PayloadTooLarge

func PayloadTooLarge(msg string) *Error

PayloadTooLarge creates a payload too large error (413).

func RateLimited

func RateLimited(msg string) *Error

RateLimited creates a rate limit error (429).

func RequestTimeout

func RequestTimeout(msg string) *Error

RequestTimeout creates a request timeout error (408). This is for client-side timeouts, distinct from 504 Gateway Timeout.

func Timeout

func Timeout(msg string) *Error

Timeout creates a timeout error (504).

func Timeoutf added in v1.1.0

func Timeoutf(format string, args ...any) *Error

Timeoutf creates a timeout error (504) with a formatted message.

func Unauthorized

func Unauthorized(msg string) *Error

Unauthorized creates an unauthorized error (401).

func Unauthorizedf added in v1.1.0

func Unauthorizedf(format string, args ...any) *Error

Unauthorizedf creates an unauthorized error (401) with a formatted message.

func Unavailable

func Unavailable(msg string) *Error

Unavailable creates an unavailable error (503).

func Unavailablef added in v1.1.0

func Unavailablef(format string, args ...any) *Error

Unavailablef creates an unavailable error (503) with a formatted message.

func UnprocessableEntity

func UnprocessableEntity(msg string) *Error

UnprocessableEntity creates an unprocessable entity error (422). Useful for semantic validation errors that differ from 400.

func Validation

func Validation(fields FieldErrors) *Error

Validation creates a validation error with field-level details.

Example

ExampleValidation demonstrates field-level validation errors.

package main

import (
	"fmt"

	errenvelope "github.com/blackwell-systems/err-envelope"
)

func main() {
	err := errenvelope.Validation(errenvelope.FieldErrors{
		"email":    "must be a valid email address",
		"age":      "must be at least 18",
		"password": "must be at least 8 characters",
	})

	fmt.Printf("Code: %s\n", err.Code)
	fmt.Printf("Status: %d\n", err.Status)
	fmt.Printf("Retryable: %v\n", err.Retryable)
}
Output:

Code: VALIDATION_FAILED
Status: 400
Retryable: false

func Wrap

func Wrap(code Code, status int, msg string, cause error) *Error

Wrap creates a new Error that wraps an underlying cause.

func Wrapf added in v1.1.0

func Wrapf(code Code, status int, format string, cause error, args ...any) *Error

Wrapf creates a new Error that wraps an underlying cause with a formatted message. Mirrors fmt.Errorf ergonomics while preserving error chain.

func (*Error) Error

func (e *Error) Error() string

func (*Error) LogValue

func (e *Error) LogValue() slog.Value

LogValue implements slog.LogValuer for structured logging.

func (*Error) MarshalJSON added in v1.1.0

func (e *Error) MarshalJSON() ([]byte, error)

MarshalJSON implements custom JSON serialization to include retry_after as a human-readable string. When RetryAfter is set, it appears in the JSON response as "retry_after": "30s" or "5m0s".

func (*Error) Unwrap

func (e *Error) Unwrap() error

func (*Error) WithDetails

func (e *Error) WithDetails(details any) *Error

WithDetails adds structured details to the error. Returns a copy to avoid mutating shared error instances.

func (*Error) WithRetryAfter

func (e *Error) WithRetryAfter(d time.Duration) *Error

WithRetryAfter sets the retry-after duration for rate-limited responses. The duration will be sent as a Retry-After header (in seconds). Returns a copy to avoid mutating shared error instances.

func (*Error) WithRetryable

func (e *Error) WithRetryable(v bool) *Error

WithRetryable sets whether the error is retryable. Returns a copy to avoid mutating shared error instances.

func (*Error) WithStatus

func (e *Error) WithStatus(status int) *Error

WithStatus overrides the HTTP status code. Returns a copy to avoid mutating shared error instances.

func (*Error) WithTraceID

func (e *Error) WithTraceID(id string) *Error

WithTraceID adds a trace ID for distributed tracing. Returns a copy to avoid mutating shared error instances.

type FieldErrors

type FieldErrors map[string]string

FieldErrors is a simple, library-agnostic validation shape.

type ValidationDetails

type ValidationDetails struct {
	Fields FieldErrors `json:"fields"`
}

ValidationDetails holds field-level validation errors.

Directories

Path Synopsis
examples
nethttp command
integrations
chi
Package chi provides thin adapters for using err-envelope with chi router.
Package chi provides thin adapters for using err-envelope with chi router.
echo
Package echo provides adapters for using err-envelope with Echo framework.
Package echo provides adapters for using err-envelope with Echo framework.
gin
Package gin provides adapters for using err-envelope with Gin framework.
Package gin provides adapters for using err-envelope with Gin framework.

Jump to

Keyboard shortcuts

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