apis

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Nov 7, 2025 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package apis defines the public Go-level contracts for dirpx error handling.

The goal of this package is to provide *small, composable* interfaces that other dirpx packages can depend on without importing the concrete error implementation (which will live in other subpackages, e.g. derrors/errors, derrors/code, derrors/reason, etc.).

In other words: this package is the "surface" that HTTP adapters, gRPC adapters, validation code and business logic can target. Concrete error types should implement these interfaces, but callers should not rely on the concrete types.

This package must remain lightweight and should not introduce heavy dependencies, so it only contains interfaces and very small view types.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CausedError

type CausedError interface {
	error

	// Cause returns the underlying error that triggered this error, if any.
	// May return nil.
	Cause() error
}

CausedError represents an error that exposes its underlying cause.

While Go 1.13 introduced errors.Unwrap, having this interface in apis lets us work with wrapped errors even in places where we don't want to depend on errors.As / errors.Is directly, or where we want to keep the contract explicit.

Implementations SHOULD return the direct, immediate cause of the error. If there is no underlying cause, they SHOULD return nil.

type CodedError

type CodedError interface {
	error

	// ErrorCode returns the machine-readable error code.
	//
	// The returned value MUST be non-empty and MUST already be normalized
	// according to the rules of the derrors subsystem. Callers should not try
	// to "fix" or "guess" the value here — if it's invalid, it should be
	// handled as an internal error at the boundary.
	ErrorCode() string
}

CodedError represents an error that is classified into a well-defined, machine-readable error *code*.

A code usually denotes a broad category, such as:

  • "invalid" — validation failed,
  • "not_found" — a referenced object does not exist,
  • "conflict" — concurrent modification or version mismatch,
  • "internal" — unexpected server-side failure.

Codes are intended to be stable and enumerable. They are the primary value that higher-level adapters (HTTP, gRPC) will use to decide which status code to return to the client.

Implementations are expected to return a *canonicalized* code string — i.e., normalized to the format enforced by the derrors/code package (lowercase, underscores, length limits, etc.). Adapters should treat unknown or empty codes as internal/server errors.

type Detail

type Detail struct {
	// Type is a short classifier of the detail, e.g. "field", "conflict",
	// "extra", "missing", etc. Callers MAY leave it empty, but providing it
	// makes client-side handling simpler.
	Type string `json:"type,omitempty"`

	// Field carries the logical path to the failing field, e.g.
	// "metadata.name" or "spec.replicas". For non-field errors this may be
	// empty.
	Field string `json:"field,omitempty"`

	// Reason is a short, human-friendly explanation, e.g. "required",
	// "not_unique", "invalid_format". This is NOT the same as the top-level
	// error reason, but often corresponds to it.
	Reason string `json:"reason,omitempty"`

	// Info carries optional extra structured data (for example, allowed
	// values, maximum length, conflicting resource name, etc.). Keys and
	// values should be chosen so that they survive JSON/proto round-trips.
	Info map[string]string `json:"info,omitempty"`
}

Detail represents a single structured piece of information attached to an error. This is a *view type* — small, transport-friendly, and suitable for JSON or proto mapper.

We keep it in apis so that different parts of the system (validators, HTTP/gRPC adapters, loggers) can speak about "details" without importing the concrete error implementation.

Typical usages:

  • report which field failed validation;
  • report expected vs actual values;
  • report conflicting resource versions.

type DetailedError

type DetailedError interface {
	error

	// ErrorDetails returns structured details of the error. May return nil.
	ErrorDetails() []Detail
}

DetailedError represents an error that exposes zero or more structured details. This is especially useful for validation scenarios where multiple fields may fail at once and the caller needs to show *all* of them.

Implementations SHOULD return a slice that is safe to iterate over and that will not be modified by the callee. Returning nil is allowed and simply means "no extra details".

type ErrorDescriptor

type ErrorDescriptor struct {
	// Code is the canonical error code, e.g. "invalid", "not_found",
	// "already_exists".
	//
	// Implementations SHOULD store only normalized, validated codes here.
	Code string `json:"code"`

	// Reason is the more specific sub-classification, e.g. "schema.group",
	// "resource.missing".
	//
	// It MAY be empty when the descriptor applies to the whole code.
	// Implementations SHOULD store only normalized, validated reasons here.
	Reason string `json:"reason,omitempty"`

	// HTTPStatus is an optional HTTP status that should be used when this
	// (code, reason) is exposed over HTTP. A value of 0 means "not specified".
	HTTPStatus int `json:"http_status,omitempty"`

	// GRPCCode is an optional gRPC status code (as integer) that should be
	// used when this (code, reason) is exposed over gRPC. A value of 0 means
	// "not specified".
	GRPCCode int `json:"grpc_code,omitempty"`

	// Message is an optional human-friendly default message or template that
	// can be used when the error instance itself did not provide one.
	Message string `json:"message,omitempty"`
}

ErrorDescriptor is a flat, transport-friendly description of a known (code, reason) pair.

This type intentionally uses strings (not the internal Code / Reason value types) so that it can live in the public "apis" layer and be used by adapters (HTTP, gRPC) and by user-defined registries.

Implementations may choose to store a richer descriptor internally, but this shape is what the rest of the system can rely on.

type ErrorView

type ErrorView struct {
	// Code is the canonical error code, e.g. "invalid", "not_found",
	// "already_exists".
	//
	// Implementations SHOULD store only normalized, validated codes here.
	Code string `json:"code"`
	// Reason is the more specific sub-classification, e.g. "schema.group",
	// "resource.missing".
	//
	// It MAY be empty when the descriptor applies to the whole code.
	// Implementations SHOULD store only normalized, validated reasons here.
	Reason string `json:"reason,omitempty"`
	// Message is an optional human-friendly message.
	//
	// This is typically either the error's own message or a default message
	// taken from the descriptor.
	Message string `json:"message,omitempty"`
	// Details is an optional list of additional details about the error.
	//
	// The exact shape of each detail is implementation-specific.
	Details []Detail `json:"details,omitempty"`
}

ErrorView is a minimal, serializable representation of an error.

This is *not* the concrete error type used internally — it is the shape that we are comfortable exposing over the wire or logging. Keeping it here (in apis) allows both HTTP and gRPC adapters to share the same struct.

type Mapper

type Mapper interface {
	// HTTPStatus returns the HTTP status code for the given error code and reason.
	// If no reason-specific rule exists, the mapper must fall back to the code-level rule.
	HTTPStatus(c code.Code, r reason.Reason) int

	// GRPCStatus returns the gRPC status code for the given error code and reason.
	// If no reason-specific rule exists, the mapper must fall back to the code-level rule.
	GRPCStatus(c code.Code, r reason.Reason) codes.Code

	// Status resolves both HTTP and gRPC in a single call, using the same matching logic.
	Status(c code.Code, r reason.Reason) Status

	// Explain returns a human-readable description of which rule matched.
	// Implementations may return an empty string in production builds.
	Explain(c code.Code, r reason.Reason) string
}

Mapper is an immutable, concurrency-safe view of the mapper rules. It resolves a logical derrors code (and optionally a reason) into transport statuses for HTTP and gRPC.

type ReasonedError

type ReasonedError interface {
	error

	// ErrorReason returns the specific error reason.
	//
	// The returned value MAY be empty if the error does not provide a more
	// specific sub-classification. Callers should be prepared to handle the
	// empty case.
	ErrorReason() string
}

ReasonedError represents an error that provides a more specific, contextual *reason* in addition to the high-level code.

While the code answers the question "what kind of error is this?", the reason answers "which exact subcase of that error happened?".

Examples:

code:   "invalid"
reason: "schema.group" -> the group name in schema is invalid

code:   "not_found"
reason: "resource.missing" -> the referenced resource does not exist

Reasons are typically hierarchical, dot-separated strings, and are expected to be validated/normalized by the derrors/reason package.

Having a separate interface for reasons allows code to gracefully degrade: if an error does not provide a reason, the caller can still act on the code.

type Status

type Status struct {
	HTTP int        // Resolved HTTP status code (net/http compatible).
	GRPC codes.Code // Resolved gRPC status code.
}

Status represents a resolved pair of transport statuses for a single error. It is the final output of the mapper and can be written directly to HTTP/gRPC.

type ViewProvider

type ViewProvider interface {
	error

	// ErrorView returns a transport-friendly snapshot of the error.
	ErrorView() ErrorView
}

ViewProvider is implemented by errors that can produce a transport-friendly, self-contained representation of themselves.

This is useful for HTTP/gRPC adapters that want to send "the canonical form" of the error to the client without having to know about the concrete error type.

The returned view MUST be safe to marshal (to JSON/proto) and SHOULD contain all information that is safe to disclose to the client.

Jump to

Keyboard shortcuts

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