api

package module
v0.10.0 Latest Latest
Warning

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

Go to latest
Published: Apr 30, 2026 License: EUPL-1.2 Imports: 66 Imported by: 0

README

dappco.re/go/api

dappco.re/go/api is the Gin-based HTTP framework used by the Core Go ecosystem. It provides a small Engine type, option-driven middleware configuration, route group mounting, response envelopes, OpenAPI 3.1 generation, SDK export/codegen helpers, SSE and WebSocket wiring, GraphQL hosting, Authentik identity middleware, and the core api CLI commands.

The package is a library first. Applications construct an engine, register one or more RouteGroup implementations, then either call Serve(ctx) or use Handler() with their own server.

engine, err := api.New(
	api.WithAddr(":8080"),
	api.WithRequestID(),
	api.WithResponseMeta(),
	api.WithSwagger("Core API", "Core service endpoints", "1.0.0"),
)
if err != nil {
	return err
}
engine.Register(myRoutes)
return engine.Serve(ctx)

Repository Shape

The root package contains the HTTP engine and most middleware. cmd/api registers Core CLI subcommands for OpenAPI export and SDK generation. cmd/gateway is a runnable gateway that mounts selected Core provider packages behind one API engine. pkg/provider discovers and proxies provider manifests. pkg/stream contains a declarative stream route group for SSE and WebSocket handlers.

Local Verification

Run the repository with the workspace disabled when checking this module in isolation:

GOWORK=off go mod tidy
GOWORK=off go vet ./...
GOWORK=off go test -count=1 ./...
gofmt -l .
bash /Users/snider/Code/core/go/tests/cli/v090-upgrade/audit.sh .

The audit is part of the development contract. Public symbols need sibling triplet tests and examples, Core wrappers are used instead of banned standard library imports, and generated AX7 dump files are not accepted.

Documentation

Overview

Package api provides a Gin-based REST framework with OpenAPI generation. Subsystems implement RouteGroup to register their own endpoints.

Index

Examples

Constants

View Source
const (
	// BrotliBestSpeed is the lowest (fastest) Brotli compression level.
	BrotliBestSpeed = brotli.BestSpeed

	// BrotliBestCompression is the highest (smallest output) Brotli level.
	BrotliBestCompression = brotli.BestCompression

	// BrotliDefaultCompression is the default Brotli compression level.
	BrotliDefaultCompression = brotli.DefaultCompression
)
View Source
const (
	// WebhookEventWorkspaceCreated fires when a new workspace is provisioned.
	WebhookEventWorkspaceCreated = "workspace.created"
	// WebhookEventWorkspaceDeleted fires when a workspace is permanently removed.
	WebhookEventWorkspaceDeleted = "workspace.deleted"
	// WebhookEventSubscriptionChanged fires when a subscription plan changes.
	WebhookEventSubscriptionChanged = "subscription.changed"
	// WebhookEventSubscriptionCancelled fires when a subscription is cancelled.
	WebhookEventSubscriptionCancelled = "subscription.cancelled"
	// WebhookEventBiolinkCreated fires when a new biolink page is created.
	WebhookEventBiolinkCreated = "biolink.created"
	// WebhookEventLinkClicked fires when a tracked short link is clicked.
	// High-volume event — recipients should opt in explicitly.
	WebhookEventLinkClicked = "link.clicked"
	// WebhookEventTicketCreated fires when a support ticket is opened.
	WebhookEventTicketCreated = "ticket.created"
	// WebhookEventTicketReplied fires when a support ticket receives a reply.
	WebhookEventTicketReplied = "ticket.replied"
)

Canonical webhook event identifiers from RFC §6. These constants mirror the PHP-side event catalogue so Go senders and receivers reference the same namespaced strings.

evt := api.WebhookEventLinkClicked // "link.clicked"
View Source
const (
	// WebhookSignatureHeader is the response/request header that carries the
	// HMAC-SHA256 hex digest of a signed webhook payload.
	WebhookSignatureHeader = "X-Webhook-Signature"

	// WebhookTimestampHeader is the response/request header that carries the
	// Unix timestamp used to derive the signature.
	WebhookTimestampHeader = "X-Webhook-Timestamp"

	// DefaultWebhookTolerance is the maximum age of a webhook timestamp the
	// signer will accept. Five minutes mirrors the PHP-side default and
	// allows for reasonable clock skew between sender and receiver.
	DefaultWebhookTolerance = 5 * time.Minute
)

Variables

View Source
var (
	// ErrHTTP3NotConfigured is returned when ServeH3 is called without
	// enabling HTTP/3 via WithHTTP3.
	ErrHTTP3NotConfigured = core.NewError("api: HTTP/3 is not configured")

	// ErrHTTP3TLSRequired is returned when ServeH3 is called without TLS.
	ErrHTTP3TLSRequired = core.NewError("api: HTTP/3 requires TLS configuration")

	// ErrNilContext is returned when ServeH3 is called with a nil context.
	ErrNilContext = core.NewError("api: context is nil")
)

Functions

func ApiSunset

func ApiSunset(sunsetDate, replacement string) gin.HandlerFunc

ApiSunset returns middleware that marks a route or group as deprecated.

The middleware appends standard deprecation headers to every response: Deprecation, optional Sunset, optional Link, optional API-Suggested-Replacement, and X-API-Warn. Existing header values are preserved so downstream middleware and handlers can keep their own link relations or warning metadata.

Example:

rg.Use(api.ApiSunset("2025-06-01", "/api/v2/users"))
Example (Sunset)
func() {
	defer func() { _ = recover() }()
	_ = ApiSunset("", "")
}()
coretest.Println("done")
Output:
done

func ApiSunsetWith

func ApiSunsetWith(sunsetDate, replacement string, opts ...SunsetOption) gin.HandlerFunc

ApiSunsetWith is the extensible form of ApiSunset. It accepts SunsetOption values to attach optional metadata such as the deprecation notice URL.

Example:

rg.Use(api.ApiSunsetWith(
    "2026-04-30",
    "POST /api/v2/billing/invoices",
    api.WithSunsetNoticeURL("https://docs.api.dappco.re/deprecation/billing"),
))
Example (Sunset)
func() {
	defer func() { _ = recover() }()
	_ = ApiSunsetWith("", "")
}()
coretest.Println("done")
Output:
done

func ExportSpec

func ExportSpec(w io.Writer, format string, builder *SpecBuilder, groups []RouteGroup) (
	_ error,
)

ExportSpec generates the OpenAPI spec and writes it to w. Format must be "json" or "yaml".

Example:

_ = api.ExportSpec(core.Stdout(), "yaml", builder, engine.Groups())
Example (Export)
func() {
	defer func() { _ = recover() }()
	_ = ExportSpec(nil, "", nil, nil)
}()
coretest.Println("done")
Output:
done

func ExportSpecIter

func ExportSpecIter(w io.Writer, format string, builder *SpecBuilder, groups iter.Seq[RouteGroup]) (
	_ error,
)

ExportSpecIter generates the OpenAPI spec from an iterator and writes it to w. Format must be "json" or "yaml".

Example:

_ = api.ExportSpecIter(core.Stdout(), "json", builder, api.RegisteredSpecGroupsIter())
Example (Export)
func() {
	defer func() { _ = recover() }()
	_ = ExportSpecIter(nil, "", nil, nil)
}()
coretest.Println("done")
Output:
done

func ExportSpecToFile

func ExportSpecToFile(path, format string, builder *SpecBuilder, groups []RouteGroup) (
	_ error,
)

ExportSpecToFile writes the spec to the given path. The parent directory is created if it does not exist.

Example:

_ = api.ExportSpecToFile("./api/openapi.yaml", "yaml", builder, engine.Groups())
Example (Export)
func() {
	defer func() { _ = recover() }()
	_ = ExportSpecToFile("", "", nil, nil)
}()
coretest.Println("done")
Output:
done

func ExportSpecToFileIter

func ExportSpecToFileIter(path, format string, builder *SpecBuilder, groups iter.Seq[RouteGroup]) (
	_ error,
)

ExportSpecToFileIter writes the OpenAPI spec from an iterator to the given path. The parent directory is created if it does not exist.

Example:

_ = api.ExportSpecToFileIter("./api/openapi.json", "json", builder, api.RegisteredSpecGroupsIter())
Example (Export)
func() {
	defer func() { _ = recover() }()
	_ = ExportSpecToFileIter("", "", nil, nil)
}()
coretest.Println("done")
Output:
done

func GenerateWebhookSecret

func GenerateWebhookSecret() (
	string,
	error,
)

GenerateWebhookSecret returns a hex-encoded 32-byte random string suitable for use as a webhook signing secret. Output length is 64 characters.

secret, err := api.GenerateWebhookSecret()
// secret = "9f1a..." (64 hex chars)
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	_, _ = GenerateWebhookSecret()
}()
coretest.Println("done")
Output:
done

func GetLocale

func GetLocale(c *gin.Context) string

GetLocale returns the detected locale for the current request. Returns "en" if the i18n middleware was not applied.

Example:

locale := api.GetLocale(c)
Example (I18n)
func() {
	defer func() { _ = recover() }()
	_ = GetLocale(nil)
}()
coretest.Println("done")
Output:
done

func GetMessage

func GetMessage(c *gin.Context, key string) (string, bool)

GetMessage looks up a localised message by key for the current request. Returns the message string and true if found, or empty string and false if the key does not exist or the i18n middleware was not applied.

Example:

msg, ok := api.GetMessage(c, "greeting")
Example (I18n)
func() {
	defer func() { _ = recover() }()
	_, _ = GetMessage(nil, "")
}()
coretest.Println("done")
Output:
done

func GetRequestDuration

func GetRequestDuration(c *gin.Context) time.Duration

GetRequestDuration returns the elapsed time since requestIDMiddleware started handling the request. Returns 0 when the middleware was not applied.

Example:

d := api.GetRequestDuration(c)
Example (Middleware)
func() {
	defer func() { _ = recover() }()
	_ = GetRequestDuration(nil)
}()
coretest.Println("done")
Output:
done

func GetRequestID

func GetRequestID(c *gin.Context) string

GetRequestID returns the request ID assigned by requestIDMiddleware. Returns an empty string when the middleware was not applied.

Example:

id := api.GetRequestID(c)
Example (Middleware)
func() {
	defer func() { _ = recover() }()
	_ = GetRequestID(nil)
}()
coretest.Println("done")
Output:
done

func IsKnownWebhookEvent

func IsKnownWebhookEvent(name string) bool

IsKnownWebhookEvent reports whether the given event name is one of the canonical identifiers documented in RFC §6.

if !api.IsKnownWebhookEvent(evt) {
    return core.NewError("unknown webhook event")
}
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	_ = IsKnownWebhookEvent("")
}()
coretest.Println("done")
Output:
done

func IsValidMCPServerID

func IsValidMCPServerID(id string) bool

IsValidMCPServerID reports whether id is safe to use as an MCP HTTP bridge server_id path segment or filesystem-backed lookup key.

Example (Bridge)
func() {
	defer func() { _ = recover() }()
	_ = IsValidMCPServerID("")
}()
coretest.Println("done")
Output:
done

func NewTracerProvider

func NewTracerProvider(exporter sdktrace.SpanExporter) *sdktrace.TracerProvider

NewTracerProvider creates a TracerProvider configured with the given SpanExporter and returns it. The caller is responsible for calling Shutdown on the returned provider when the application exits.

This is a convenience helper for tests and simple deployments. Production setups should build their own TracerProvider with batching, resource attributes, and appropriate exporters.

Example:

tp := api.NewTracerProvider(exporter)
_ = tp.Shutdown(context.Background())
Example (Tracing)
func() {
	defer func() { _ = recover() }()
	_ = NewTracerProvider(nil)
}()
coretest.Println("done")
Output:
done

func RegisterSpecGroups

func RegisterSpecGroups(groups ...RouteGroup)

RegisterSpecGroups adds route groups to the package-level spec registry. Nil groups are ignored. Registered groups are returned by RegisteredSpecGroups in the order they were added.

Example:

api.RegisterSpecGroups(api.NewToolBridge("/mcp"))
Example (SpecRegistry)
func() {
	defer func() { _ = recover() }()
	RegisterSpecGroups()
}()
coretest.Println("done")
Output:
done

func RegisterSpecGroupsIter

func RegisterSpecGroupsIter(groups iter.Seq[RouteGroup])

RegisterSpecGroupsIter adds route groups from an iterator to the package-level spec registry.

Nil groups are ignored. Registered groups are returned by RegisteredSpecGroups in the order they were added.

Example:

api.RegisterSpecGroupsIter(api.RegisteredSpecGroupsIter())
Example (SpecRegistry)
func() {
	defer func() { _ = recover() }()
	RegisterSpecGroupsIter(nil)
}()
coretest.Println("done")
Output:
done

func RegisteredSpecGroupsIter

func RegisteredSpecGroupsIter() iter.Seq[RouteGroup]

RegisteredSpecGroupsIter returns an iterator over the route groups registered for CLI-generated OpenAPI documents.

The iterator snapshots the current registry contents so callers can range over it without holding the registry lock.

Example:

for g := range api.RegisteredSpecGroupsIter() {
	_ = g
}
Example (SpecRegistry)
func() {
	defer func() { _ = recover() }()
	_ = RegisteredSpecGroupsIter()
}()
coretest.Println("done")
Output:
done

func RequireAuth

func RequireAuth() gin.HandlerFunc

RequireAuth is Gin middleware that rejects unauthenticated requests. It checks for a user set by the Authentik middleware and returns 401 when none is present.

Example:

r.GET("/private", api.RequireAuth(), handler)
Example (Authentik)
func() {
	defer func() { _ = recover() }()
	_ = RequireAuth()
}()
coretest.Println("done")
Output:
done

func RequireGroup

func RequireGroup(group string) gin.HandlerFunc

RequireGroup is Gin middleware that rejects requests from users who do not belong to the specified group. Returns 401 when no user is present and 403 when the user lacks the required group membership.

Example:

r.GET("/admin", api.RequireGroup("admins"), handler)
Example (Authentik)
func() {
	defer func() { _ = recover() }()
	_ = RequireGroup("")
}()
coretest.Println("done")
Output:
done

func ResetSpecGroups

func ResetSpecGroups()

ResetSpecGroups clears the package-level spec registry. It is primarily intended for tests that need to isolate global state.

Example:

api.ResetSpecGroups()
Example (SpecRegistry)
func() {
	defer func() { _ = recover() }()
	ResetSpecGroups()
}()
coretest.Println("done")
Output:
done

func SpecGroupsIter

func SpecGroupsIter(extra RouteGroup) iter.Seq[RouteGroup]

SpecGroupsIter returns the registered spec groups plus one optional extra group, deduplicated by group identity.

The iterator snapshots the registry before yielding so callers can range over it without holding the registry lock.

Example:

for g := range api.SpecGroupsIter(api.NewToolBridge("/tools")) {
	_ = g
}
Example (SpecRegistry)
func() {
	defer func() { _ = recover() }()
	_ = SpecGroupsIter(nil)
}()
coretest.Println("done")
Output:
done

func SupportedLanguages

func SupportedLanguages() []string

SupportedLanguages returns the list of supported SDK target languages in sorted order for deterministic output.

Example:

langs := api.SupportedLanguages()
Example (Codegen)
func() {
	defer func() { _ = recover() }()
	_ = SupportedLanguages()
}()
coretest.Println("done")
Output:
done

func SupportedLanguagesIter

func SupportedLanguagesIter() iter.Seq[string]

SupportedLanguagesIter returns an iterator over supported SDK target languages in sorted order.

Example:

for lang := range api.SupportedLanguagesIter() {
	_ = lang
}
Example (Codegen)
func() {
	defer func() { _ = recover() }()
	_ = SupportedLanguagesIter()
}()
coretest.Println("done")
Output:
done

func ValidateWebhookURL

func ValidateWebhookURL(raw string) (
	_ error,
)

ValidateWebhookURL rejects webhook targets that are not absolute HTTP(S) URLs or that resolve to loopback, private, link-local, multicast, or other reserved IP space.

if err := api.ValidateWebhookURL("https://hooks.example.com/inbox"); err != nil {
    return err
}
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	_ = ValidateWebhookURL("")
}()
coretest.Println("done")
Output:
done

func WebhookEvents

func WebhookEvents() []string

WebhookEvents returns the canonical list of webhook event identifiers documented in RFC §6. The order is stable: catalogue groups share a prefix (workspace → subscription → biolink → link → ticket).

for _, evt := range api.WebhookEvents() {
    registry.Enable(evt)
}
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	_ = WebhookEvents()
}()
coretest.Println("done")
Output:
done

Types

type ActionHint

type ActionHint struct {
	Name    string `json:"name,omitempty"`
	Label   string `json:"label,omitempty"`
	Method  string `json:"method,omitempty"`
	Variant string `json:"variant,omitempty"`
}

ActionHint describes an inline action a UI can render for an operation.

type AuthentikConfig

type AuthentikConfig struct {
	// Issuer is the OIDC issuer URL (e.g. https://auth.example.com/application/o/my-app/).
	Issuer string

	// ClientID is the OAuth2 client identifier.
	ClientID string

	// TrustedProxy enables reading X-authentik-* headers set by a reverse proxy.
	// When false, headers are ignored to prevent spoofing from untrusted sources.
	TrustedProxy bool

	// PublicPaths lists additional paths that do not require authentication.
	// /health and the configured Swagger UI path are always public.
	PublicPaths []string
}

AuthentikConfig holds settings for the Authentik forward-auth integration.

Example:

cfg := api.AuthentikConfig{Issuer: "https://auth.example.com/", ClientID: "core-api"}

type AuthentikUser

type AuthentikUser struct {
	Username     string   `json:"username"`
	Email        string   `json:"email"`
	Name         string   `json:"name"`
	UID          string   `json:"uid"`
	Groups       []string `json:"groups,omitempty"`
	Entitlements []string `json:"entitlements,omitempty"`
	JWT          string   `json:"-"`
}

AuthentikUser represents an authenticated user extracted from Authentik forward-auth headers or a validated JWT.

Example:

user := &api.AuthentikUser{Username: "alice", Groups: []string{"admins"}}

func GetUser

func GetUser(c *gin.Context) *AuthentikUser

GetUser retrieves the AuthentikUser from the Gin context. Returns nil when no user has been set (unauthenticated request or middleware not active).

Example:

user := api.GetUser(c)
Example (Authentik)
func() {
	defer func() { _ = recover() }()
	_ = GetUser(nil)
}()
coretest.Println("done")
Output:
done

func (*AuthentikUser) HasGroup

func (u *AuthentikUser) HasGroup(group string) bool

HasGroup reports whether the user belongs to the named group.

Example:

user.HasGroup("admins")
Example (Authentik)
func() {
	defer func() { _ = recover() }()
	var subject *AuthentikUser
	_ = subject.HasGroup("")
}()
coretest.Println("done")
Output:
done

type CacheConfig

type CacheConfig struct {
	Enabled    bool
	TTL        time.Duration
	MaxEntries int
	MaxBytes   int
}

CacheConfig captures the configured response cache settings for an Engine.

It is intentionally small and serialisable so callers can inspect the active cache policy without needing to rebuild middleware state.

Example:

cfg := api.CacheConfig{Enabled: true, TTL: 5 * time.Minute}

type ChatChoice

type ChatChoice struct {
	Index        int         `json:"index"`
	Message      ChatMessage `json:"message"`
	FinishReason string      `json:"finish_reason"`
}

ChatChoice is a single response option.

choice.Message.Content  // The generated text
choice.FinishReason     // "stop", "length", or "error"

type ChatChunkChoice

type ChatChunkChoice struct {
	Index        int              `json:"index"`
	Delta        ChatMessageDelta `json:"delta"`
	FinishReason *string          `json:"finish_reason"`
}

ChatChunkChoice is a streaming delta.

delta.Content // New token(s) in this chunk

type ChatCompletionChunk

type ChatCompletionChunk struct {
	ID      string            `json:"id"`
	Object  string            `json:"object"`
	Created int64             `json:"created"`
	Model   string            `json:"model"`
	Choices []ChatChunkChoice `json:"choices"`
	Thought *string           `json:"thought,omitempty"`
}

ChatCompletionChunk is a single SSE chunk during streaming.

chunk.Choices[0].Delta.Content // Partial token text

type ChatCompletionRequest

type ChatCompletionRequest struct {
	Model       string        `json:"model"`
	Messages    []ChatMessage `json:"messages"`
	Temperature *float32      `json:"temperature,omitempty"`
	TopP        *float32      `json:"top_p,omitempty"`
	TopK        *int          `json:"top_k,omitempty"`
	MaxTokens   *int          `json:"max_tokens,omitempty"`
	Stream      bool          `json:"stream,omitempty"`
	Stop        chatStopList  `json:"stop,omitempty"` // Stop sequences, excluded from the final completion text. Accepts a single string or an array (OpenAI compat).
	User        string        `json:"user,omitempty"`
}

ChatCompletionRequest is the OpenAI-compatible request body.

body := ChatCompletionRequest{
    Model:    "lemer",
    Messages: []ChatMessage{{Role: "user", Content: "What is 2+2?"}},
    Stream:   true,
}

type ChatCompletionResponse

type ChatCompletionResponse struct {
	ID      string       `json:"id"`
	Object  string       `json:"object"`
	Created int64        `json:"created"`
	Model   string       `json:"model"`
	Choices []ChatChoice `json:"choices"`
	Usage   ChatUsage    `json:"usage"`
	Thought *string      `json:"thought,omitempty"`
}

ChatCompletionResponse is the OpenAI-compatible response body.

resp.Choices[0].Message.Content // "4"

type ChatMessage

type ChatMessage struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

ChatMessage is a single turn in a conversation.

msg := ChatMessage{Role: "user", Content: "Hello"}

type ChatMessageDelta

type ChatMessageDelta struct {
	Role    string `json:"role,omitempty"`
	Content string `json:"content,omitempty"`
}

ChatMessageDelta is the incremental content within a streaming chunk.

delta.Content // "" on first chunk (role-only), then token text

func (ChatMessageDelta) MarshalJSON

func (d ChatMessageDelta) MarshalJSON() (
	[]byte,
	error,
)

MarshalJSON preserves the OpenAI-style priming chunk shape while still omitting empty deltas for terminal chunks.

The first streaming chunk carries the assistant role and an explicit empty content string. A terminal chunk, by contrast, carries neither field.

Example (ChatCompletions)
func() {
	defer func() { _ = recover() }()
	var subject ChatMessageDelta
	_, _ = subject.MarshalJSON()
}()
coretest.Println("done")
Output:
done

type ChatUsage

type ChatUsage struct {
	PromptTokens     int `json:"prompt_tokens"`
	CompletionTokens int `json:"completion_tokens"`
	TotalTokens      int `json:"total_tokens"`
}

ChatUsage reports token consumption for the request.

usage.TotalTokens // PromptTokens + CompletionTokens

type Describable

type Describable interface {
	// Describe returns the handler's request/response description.
	Describe() RouteDescription
	// OperationID returns the OpenAPI operation identifier.
	OperationID() string
	// Tags returns the OpenAPI tags associated with the operation.
	Tags() []string
	// Summary returns a short operation summary.
	Summary() string
	// Description returns a longer operation description.
	Description() string
}

Describable allows a route handler or controller to expose OpenAPI metadata without coupling callers to RouteDescription construction details.

Example:

var d api.Describable = &myHandler{}

type DescribableGroup

type DescribableGroup interface {
	RouteGroup
	// Describe returns endpoint descriptions for OpenAPI generation.
	Describe() []RouteDescription
}

DescribableGroup extends RouteGroup with OpenAPI metadata. RouteGroups that implement this will have their endpoints included in the generated OpenAPI specification.

Example:

var dg api.DescribableGroup = &myDescribableGroup{}

type DescribableGroupIter

type DescribableGroupIter interface {
	DescribableGroup
	// DescribeIter returns endpoint descriptions for OpenAPI generation.
	DescribeIter() iter.Seq[RouteDescription]
}

DescribableGroupIter extends DescribableGroup with an iterator-based description source for callers that want to avoid slice allocation.

Example:

var dg api.DescribableGroupIter = &myDescribableGroup{}

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine is the central API server managing route groups and middleware.

Example:

engine, err := api.New(api.WithAddr(":8081"))
if err != nil {
	panic(err)
}
_ = engine.Handler()

func New

func New(opts ...Option) (
	*Engine,
	error,
)

New creates an Engine with the given options. The default listen address is ":8080".

Example:

engine, err := api.New(api.WithAddr(":8081"), api.WithResponseMeta())
if err != nil {
	panic(err)
}
Example (Api)
func() {
	defer func() { _ = recover() }()
	_, _ = New()
}()
coretest.Println("done")
Output:
done

func (*Engine) Addr

func (e *Engine) Addr() string

Addr returns the configured listen address.

Example:

engine, _ := api.New(api.WithAddr(":9090"))
addr := engine.Addr()
Example (Api)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.Addr()
}()
coretest.Println("done")
Output:
done

func (*Engine) AuthentikConfig

func (e *Engine) AuthentikConfig() AuthentikConfig

AuthentikConfig returns the configured Authentik settings for the engine.

The result snapshots the Engine state at call time and clones slices so callers can safely reuse or modify the returned value.

Example:

cfg := engine.AuthentikConfig()
Example (Authentik)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.AuthentikConfig()
}()
coretest.Println("done")
Output:
done

func (*Engine) CacheConfig

func (e *Engine) CacheConfig() CacheConfig

CacheConfig returns the currently configured response cache settings for the engine.

The result snapshots the Engine state at call time.

Example:

cfg := engine.CacheConfig()
Example (CacheConfig)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.CacheConfig()
}()
coretest.Println("done")
Output:
done

func (*Engine) Channels

func (e *Engine) Channels() []string

Channels returns all WebSocket channel names from registered StreamGroups. Groups that do not implement StreamGroup are silently skipped.

Example:

channels := engine.Channels()
Example (Api)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.Channels()
}()
coretest.Println("done")
Output:
done

func (*Engine) ChannelsIter

func (e *Engine) ChannelsIter() iter.Seq[string]

ChannelsIter returns an iterator over WebSocket channel names from registered StreamGroups.

Example:

for channel := range engine.ChannelsIter() {
	_ = channel
}
Example (Api)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.ChannelsIter()
}()
coretest.Println("done")
Output:
done

func (*Engine) GraphQLConfig

func (e *Engine) GraphQLConfig() GraphQLConfig

GraphQLConfig returns the currently configured GraphQL settings for the engine.

The result snapshots the Engine state at call time and normalises any configured URL path using the same rules as the runtime handlers.

Example:

cfg := engine.GraphQLConfig()
Example (Graphql)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.GraphQLConfig()
}()
coretest.Println("done")
Output:
done

func (*Engine) Groups

func (e *Engine) Groups() []RouteGroup

Groups returns a copy of all registered route groups.

Example:

groups := engine.Groups()
Example (Api)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.Groups()
}()
coretest.Println("done")
Output:
done

func (*Engine) GroupsIter

func (e *Engine) GroupsIter() iter.Seq[RouteGroup]

GroupsIter returns an iterator over all registered route groups.

Example:

for group := range engine.GroupsIter() {
	_ = group
}
Example (Api)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.GroupsIter()
}()
coretest.Println("done")
Output:
done

func (*Engine) Handler

func (e *Engine) Handler() http.Handler

Handler builds the Gin engine and returns it as an http.Handler. Each call produces a fresh handler reflecting the current set of groups.

Example:

handler := engine.Handler()
Example (Api)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.Handler()
}()
coretest.Println("done")
Output:
done

func (*Engine) I18nConfig

func (e *Engine) I18nConfig() I18nConfig

I18nConfig returns the configured locale and message catalogue settings for the engine.

The result snapshots the Engine state at call time and clones slices/maps so callers can safely reuse or modify the returned value.

Example:

cfg := engine.I18nConfig()
Example (I18n)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.I18nConfig()
}()
coretest.Println("done")
Output:
done

func (*Engine) OpenAPISpecBuilder

func (e *Engine) OpenAPISpecBuilder() *SpecBuilder

OpenAPISpecBuilder returns a SpecBuilder populated from the engine's current Swagger, transport, cache, i18n, and Authentik metadata.

Example:

builder := engine.OpenAPISpecBuilder()
Example (SpecBuilderHelper)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.OpenAPISpecBuilder()
}()
coretest.Println("done")
Output:
done

func (*Engine) Register

func (e *Engine) Register(group RouteGroup)

Register adds a route group to the engine.

Example:

engine.Register(myGroup)
Example (Api)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	subject.Register(nil)
}()
coretest.Println("done")
Output:
done

func (*Engine) RegisterStreamGroup

func (e *Engine) RegisterStreamGroup(group apistream.StreamGroup)

RegisterStreamGroup adds a declarative SSE/WebSocket handler group to the engine.

Example:

engine.RegisterStreamGroup(stream.NewGroup("events"))
Example (Api)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	subject.RegisterStreamGroup(nil)
}()
coretest.Println("done")
Output:
done

func (*Engine) RuntimeConfig

func (e *Engine) RuntimeConfig() RuntimeConfig

RuntimeConfig returns a stable snapshot of the engine's current runtime configuration.

The result clones the underlying snapshots so callers can safely retain or modify the returned value.

Example:

cfg := engine.RuntimeConfig()
Example (RuntimeConfig)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.RuntimeConfig()
}()
coretest.Println("done")
Output:
done

func (*Engine) Serve

func (e *Engine) Serve(ctx context.Context) (
	_ error,
)

Serve starts the HTTP server and blocks until the context is cancelled, then performs a graceful shutdown allowing in-flight requests to complete.

Example:

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_ = engine.Serve(ctx)
Example (Api)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.Serve(nil)
}()
coretest.Println("done")
Output:
done

func (*Engine) ServeH3

func (e *Engine) ServeH3(ctx context.Context, tlsConfig *tls.Config) (
	_ error,
)

ServeH3 starts the HTTP/3 QUIC server and blocks until the context is cancelled, then performs a graceful shutdown.

ServeH3 is intentionally separate from Serve so callers can run the QUIC listener alongside their existing HTTP/1.1+2 server with an explicit TLS configuration.

Example (ServeH3)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.ServeH3(nil, nil)
}()
coretest.Println("done")
Output:
done

func (*Engine) SwaggerConfig

func (e *Engine) SwaggerConfig() SwaggerConfig

SwaggerConfig returns the currently configured Swagger metadata for the engine.

The result snapshots the Engine state at call time and clones slices/maps so callers can safely reuse or modify the returned value.

Example:

cfg := engine.SwaggerConfig()
Example (SpecBuilderHelper)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.SwaggerConfig()
}()
coretest.Println("done")
Output:
done

func (*Engine) TransportConfig

func (e *Engine) TransportConfig() TransportConfig

TransportConfig returns the currently configured transport metadata for the engine.

The result snapshots the Engine state at call time and normalises any configured URL paths using the same rules as the runtime handlers.

Example:

cfg := engine.TransportConfig()
Example (Transport)
func() {
	defer func() { _ = recover() }()
	var subject *Engine
	_ = subject.TransportConfig()
}()
coretest.Println("done")
Output:
done

type EntitlementBridge

type EntitlementBridge struct {
	// contains filtered or unexported fields
}

EntitlementBridge resolves server-side entitlement gates against the authoritative PHP EntitlementService endpoint.

func NewEntitlementBridge

func NewEntitlementBridge(cfg EntitlementBridgeConfig) *EntitlementBridge

NewEntitlementBridge creates a bridge that can populate go-html's Entitlements callback without importing go-html here.

Example (Entitlements)
func() {
	defer func() { _ = recover() }()
	_ = NewEntitlementBridge(EntitlementBridgeConfig{})
}()
coretest.Println("done")
Output:
done

func (*EntitlementBridge) Callback

func (b *EntitlementBridge) Callback(ctx context.Context, workspaceID string, headers http.Header) func(feature string) bool

Callback returns the exact callback shape expected by go-html render contexts: func(feature string) bool. Errors fail closed by returning false.

Example (Entitlements)
func() {
	defer func() { _ = recover() }()
	var subject *EntitlementBridge
	_ = subject.Callback(nil, "", nil)
}()
coretest.Println("done")
Output:
done

func (*EntitlementBridge) CallbackForGin

func (b *EntitlementBridge) CallbackForGin(c *gin.Context, workspaceID string) func(feature string) bool

CallbackForGin is a convenience wrapper for Gin handlers that render go-html components.

Example (Entitlements)
func() {
	defer func() { _ = recover() }()
	var subject *EntitlementBridge
	_ = subject.CallbackForGin(nil, "")
}()
coretest.Println("done")
Output:
done

func (*EntitlementBridge) CallbackForRequest

func (b *EntitlementBridge) CallbackForRequest(r *http.Request, workspaceID string) func(feature string) bool

CallbackForRequest binds the current request context and auth/session headers to an entitlement callback suitable for server-side render contexts.

Example (Entitlements)
func() {
	defer func() { _ = recover() }()
	var subject *EntitlementBridge
	_ = subject.CallbackForRequest(nil, "")
}()
coretest.Println("done")
Output:
done

func (*EntitlementBridge) Check

func (b *EntitlementBridge) Check(ctx context.Context, workspaceID, feature string, headers http.Header) (
	bool,
	error,
)

Check returns whether feature is allowed for the current workspace. A blank workspaceID uses the current-workspace PHP route, resolved from forwarded request auth/session headers.

Example (Entitlements)
func() {
	defer func() { _ = recover() }()
	var subject *EntitlementBridge
	_, _ = subject.Check(nil, "", "", nil)
}()
coretest.Println("done")
Output:
done

type EntitlementBridgeConfig

type EntitlementBridgeConfig struct {
	// BaseURL is the PHP API origin, e.g. "https://app.example.com".
	BaseURL string

	// Token is an optional service token. When empty, request Authorization
	// headers passed to Check/Callback are forwarded instead.
	Token string

	// HTTPClient overrides the default client. When nil, a bounded-timeout
	// client is created so render-time entitlement checks fail closed.
	HTTPClient *http.Client

	// Timeout configures the default client timeout. Zero uses a safe default.
	Timeout time.Duration
}

EntitlementBridgeConfig configures the bridge from Go renderers to the PHP EntitlementService-backed API.

type Error

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

Error describes a failed API request.

Example:

err := api.Error{Code: "invalid_input", Message: "Name is required"}

type FieldHint

type FieldHint struct {
	Name       string         `json:"name,omitempty"`
	Label      string         `json:"label,omitempty"`
	Type       string         `json:"type,omitempty"`
	Required   bool           `json:"required,omitempty"`
	Validation map[string]any `json:"validation,omitempty"`
}

FieldHint describes an input field for UI rendering.

type FieldRenamer

type FieldRenamer struct {
	Fields map[string]string
}

FieldRenamer remaps top-level JSON object fields. It implements both TransformerIn[map[string]any, map[string]any] and TransformerOut[map[string]any, map[string]any].

func RenameFields

func RenameFields(fields map[string]string) FieldRenamer

RenameFields creates a top-level JSON object field renamer. The map keys are source field names and values are destination field names.

Example (Transformer)
func() {
	defer func() { _ = recover() }()
	_ = RenameFields(nil)
}()
coretest.Println("done")
Output:
done

func (FieldRenamer) TransformIn

func (r FieldRenamer) TransformIn(_ *gin.Context, payload map[string]any) (
	map[string]any,
	error,
)

TransformIn renames inbound request fields.

Example (Transformer)
func() {
	defer func() { _ = recover() }()
	var subject FieldRenamer
	_, _ = subject.TransformIn(nil, nil)
}()
coretest.Println("done")
Output:
done

func (FieldRenamer) TransformOut

func (r FieldRenamer) TransformOut(_ *gin.Context, payload map[string]any) (
	map[string]any,
	error,
)

TransformOut renames outbound response fields.

Example (Transformer)
func() {
	defer func() { _ = recover() }()
	var subject FieldRenamer
	_, _ = subject.TransformOut(nil, nil)
}()
coretest.Println("done")
Output:
done

type GraphQLConfig

type GraphQLConfig struct {
	Enabled        bool
	Path           string
	Playground     bool
	PlaygroundPath string
}

GraphQLConfig captures the configured GraphQL endpoint settings for an Engine.

It is intentionally small and serialisable so callers can inspect the active GraphQL surface without reaching into the internal handler configuration.

Example:

cfg := api.GraphQLConfig{Enabled: true, Path: "/graphql", Playground: true}

type GraphQLOption

type GraphQLOption func(*graphqlConfig)

GraphQLOption configures a GraphQL endpoint.

Example:

opts := []api.GraphQLOption{api.WithPlayground(), api.WithGraphQLPath("/gql")}

func WithGraphQLPath

func WithGraphQLPath(path string) GraphQLOption

WithGraphQLPath sets a custom URL path for the GraphQL endpoint. The default path is "/graphql".

Example:

api.WithGraphQL(schema, api.WithGraphQLPath("/gql"))
Example (Graphql)
func() {
	defer func() { _ = recover() }()
	_ = WithGraphQLPath("")
}()
coretest.Println("done")
Output:
done

func WithPlayground

func WithPlayground() GraphQLOption

WithPlayground enables the GraphQL Playground UI at {path}/playground.

Example:

api.WithGraphQL(schema, api.WithPlayground())
Example (Graphql)
func() {
	defer func() { _ = recover() }()
	_ = WithPlayground()
}()
coretest.Println("done")
Output:
done

type I18nConfig

type I18nConfig struct {
	// DefaultLocale is the fallback locale when the Accept-Language header
	// is absent or does not match any supported locale. Defaults to "en".
	DefaultLocale string

	// Supported lists the locale tags the application supports.
	// Each entry should be a BCP 47 language tag (e.g. "en", "fr", "de").
	// If empty, only the default locale is supported.
	Supported []string

	// Messages maps locale tags to key-value message pairs.
	// For example: {"en": {"greeting": "Hello"}, "fr": {"greeting": "Bonjour"}}
	// This is optional — handlers can use GetLocale() alone for custom logic.
	Messages map[string]map[string]string
}

I18nConfig configures the internationalisation middleware.

Example:

cfg := api.I18nConfig{
	DefaultLocale: "en",
	Supported:     []string{"en", "fr"},
	Messages:      map[string]map[string]string{"fr": {"greeting": "Bonjour"}},
}

type Meta

type Meta struct {
	RequestID string `json:"request_id,omitempty"`
	Duration  string `json:"duration,omitempty"`
	Page      int    `json:"page,omitempty"`
	PerPage   int    `json:"per_page,omitempty"`
	Total     int    `json:"total,omitempty"`
}

Meta carries pagination and request metadata.

Example:

meta := api.Meta{RequestID: "req_123", Duration: "12ms"}

func GetRequestMeta

func GetRequestMeta(c *gin.Context) *Meta

GetRequestMeta returns request metadata collected by requestIDMiddleware. The returned meta includes the request ID and elapsed duration when available. It returns nil when neither value is available.

Example:

meta := api.GetRequestMeta(c)
Example (Middleware)
func() {
	defer func() { _ = recover() }()
	_ = GetRequestMeta(nil)
}()
coretest.Println("done")
Output:
done

type ModelResolver

type ModelResolver struct {
	// contains filtered or unexported fields
}

ModelResolver resolves model names to loaded inference.TextModel instances.

Resolution order:

  1. Exact cache hit
  2. ~/.core/models.yaml path mapping
  3. discovery by architecture via inference.Discover()

func NewModelResolver

func NewModelResolver() *ModelResolver

NewModelResolver constructs a ModelResolver with empty caches. The returned resolver is safe for concurrent use — ResolveModel serialises cache updates through an internal core.RWMutex.

resolver := api.NewModelResolver()
engine, _ := api.New(api.WithChatCompletions(resolver))
Example (ChatCompletions)
func() {
	defer func() { _ = recover() }()
	_ = NewModelResolver()
}()
coretest.Println("done")
Output:
done

func (*ModelResolver) ResolveModel

func (r *ModelResolver) ResolveModel(name string) (
	inference.TextModel,
	error,
)

ResolveModel maps a model name to a loaded inference.TextModel. Cached models are reused. Unknown names return an error.

Example (ChatCompletions)
func() {
	defer func() { _ = recover() }()
	var subject *ModelResolver
	_, _ = subject.ResolveModel("")
}()
coretest.Println("done")
Output:
done

type OpenAPIClient

type OpenAPIClient struct {
	// contains filtered or unexported fields
}

OpenAPIClient is a small runtime client that can call operations by their OpenAPI operationId. It loads the spec once, resolves the HTTP method and path for each operation, and performs JSON request/response handling.

Example:

client := api.NewOpenAPIClient(api.WithSpec("./openapi.yaml"), api.WithBaseURL("https://api.example.com"))
data, err := client.Call("get_health", nil)

func NewOpenAPIClient

func NewOpenAPIClient(opts ...OpenAPIClientOption) *OpenAPIClient

NewOpenAPIClient constructs a runtime client for calling OpenAPI operations.

Example:

client := api.NewOpenAPIClient(api.WithSpec("./openapi.yaml"))
Example (Client)
func() {
	defer func() { _ = recover() }()
	_ = NewOpenAPIClient()
}()
coretest.Println("done")
Output:
done

func (*OpenAPIClient) Call

func (c *OpenAPIClient) Call(operationID string, params any) (
	any,
	error,
)

Call invokes the operation with the given operationId.

The params argument may be a map, struct, or nil. For convenience, a map may include `path`, "query", "header", "cookie", and "body" keys to explicitly control where the values are sent. When no explicit body is provided, requests with a declared requestBody send the remaining parameters as JSON.

Example:

data, err := client.Call("create_item", map[string]any{"name": "alpha"})
Example (Client)
func() {
	defer func() { _ = recover() }()
	var subject *OpenAPIClient
	_, _ = subject.Call("", nil)
}()
coretest.Println("done")
Output:
done

func (*OpenAPIClient) Operations

func (c *OpenAPIClient) Operations() (
	[]OpenAPIOperation,
	error,
)

Operations returns a snapshot of the operations loaded from the OpenAPI document.

Example:

ops, err := client.Operations()
Example (Client)
func() {
	defer func() { _ = recover() }()
	var subject *OpenAPIClient
	_, _ = subject.Operations()
}()
coretest.Println("done")
Output:
done

func (*OpenAPIClient) OperationsIter

func (c *OpenAPIClient) OperationsIter() (
	iter.Seq[OpenAPIOperation],
	error,
)

OperationsIter returns an iterator over the loaded OpenAPI operations.

Example:

ops, err := client.OperationsIter()
if err != nil {
	panic(err)
}
for op := range ops {
	fmt.Println(op.OperationID, op.PathTemplate)
}
Example (Client)
func() {
	defer func() { _ = recover() }()
	var subject *OpenAPIClient
	_, _ = subject.OperationsIter()
}()
coretest.Println("done")
Output:
done

func (*OpenAPIClient) Servers

func (c *OpenAPIClient) Servers() (
	[]string,
	error,
)

Servers returns a snapshot of the server URLs discovered from the OpenAPI document.

Example:

servers, err := client.Servers()
Example (Client)
func() {
	defer func() { _ = recover() }()
	var subject *OpenAPIClient
	_, _ = subject.Servers()
}()
coretest.Println("done")
Output:
done

func (*OpenAPIClient) ServersIter

func (c *OpenAPIClient) ServersIter() (
	iter.Seq[string],
	error,
)

ServersIter returns an iterator over the server URLs discovered from the OpenAPI document.

Example:

servers, err := client.ServersIter()
if err != nil {
	panic(err)
}
for server := range servers {
	fmt.Println(server)
}
Example (Client)
func() {
	defer func() { _ = recover() }()
	var subject *OpenAPIClient
	_, _ = subject.ServersIter()
}()
coretest.Println("done")
Output:
done

type OpenAPIClientOption

type OpenAPIClientOption func(*OpenAPIClient)

OpenAPIClientOption configures a runtime OpenAPI client.

Example:

client := api.NewOpenAPIClient(api.WithSpec("./openapi.yaml"))

func WithBaseURL

func WithBaseURL(baseURL string) OpenAPIClientOption

WithBaseURL sets the base URL used for outgoing requests.

Example:

client := api.NewOpenAPIClient(api.WithBaseURL("https://api.example.com"))
Example (Client)
func() {
	defer func() { _ = recover() }()
	_ = WithBaseURL("")
}()
coretest.Println("done")
Output:
done

func WithBearerToken

func WithBearerToken(token string) OpenAPIClientOption

WithBearerToken sets the Authorization bearer token used for requests.

Example:

client := api.NewOpenAPIClient(
	api.WithBaseURL("https://api.example.com"),
	api.WithBearerToken("secret-token"),
)
Example (Client)
func() {
	defer func() { _ = recover() }()
	_ = WithBearerToken("")
}()
coretest.Println("done")
Output:
done

func WithHTTPClient

func WithHTTPClient(client *http.Client) OpenAPIClientOption

WithHTTPClient sets the HTTP client used to execute requests.

Example:

client := api.NewOpenAPIClient(api.WithHTTPClient(http.DefaultClient))
Example (Client)
func() {
	defer func() { _ = recover() }()
	_ = WithHTTPClient(nil)
}()
coretest.Println("done")
Output:
done

func WithSpec

func WithSpec(path string) OpenAPIClientOption

WithSpec sets the filesystem path to the OpenAPI document.

Example:

client := api.NewOpenAPIClient(api.WithSpec("./openapi.yaml"))
Example (Client)
func() {
	defer func() { _ = recover() }()
	_ = WithSpec("")
}()
coretest.Println("done")
Output:
done

func WithSpecReader

func WithSpecReader(reader io.Reader) OpenAPIClientOption

WithSpecReader sets an in-memory or streamed OpenAPI document source. It is read once the first time the client loads its spec.

Example:

client := api.NewOpenAPIClient(api.WithSpecReader(core.NewReader(spec)))
Example (Client)
func() {
	defer func() { _ = recover() }()
	_ = WithSpecReader(nil)
}()
coretest.Println("done")
Output:
done

type OpenAPIOperation

type OpenAPIOperation struct {
	OperationID    string
	Method         string
	PathTemplate   string
	HasRequestBody bool
	Parameters     []OpenAPIParameter
}

OpenAPIOperation snapshots the public metadata for a single loaded OpenAPI operation.

Example:

ops, err := client.Operations()
if err == nil && len(ops) > 0 {
	fmt.Println(ops[0].OperationID, ops[0].PathTemplate)
}

type OpenAPIParameter

type OpenAPIParameter struct {
	Name     string
	In       string
	Required bool
	Schema   map[string]any
}

OpenAPIParameter snapshots a single OpenAPI parameter definition.

Example:

op, err := client.Operations()
if err == nil && len(op) > 0 && len(op[0].Parameters) > 0 {
	fmt.Println(op[0].Parameters[0].Name, op[0].Parameters[0].In)
}

type Option

type Option func(*Engine)

Option configures an Engine during construction.

Example:

engine, _ := api.New(api.WithAddr(":8080"))

func WithAddr

func WithAddr(addr string) Option

WithAddr sets the listen address for the server.

Example:

api.New(api.WithAddr(":8443"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithAddr("")
}()
coretest.Println("done")
Output:
done

func WithAuthentik

func WithAuthentik(cfg AuthentikConfig) Option

WithAuthentik adds Authentik forward-auth middleware that extracts user identity from X-authentik-* headers set by a trusted reverse proxy. The middleware is permissive: unauthenticated requests are allowed through.

Example:

api.New(api.WithAuthentik(api.AuthentikConfig{TrustedProxy: true}))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithAuthentik(AuthentikConfig{})
}()
coretest.Println("done")
Output:
done

func WithAuthz

func WithAuthz(enforcer *casbin.Enforcer) Option

WithAuthz adds Casbin policy-based authorisation middleware via gin-contrib/authz. The caller provides a pre-configured Casbin enforcer holding the desired model and policy rules. The middleware extracts the subject from HTTP Basic Authentication, evaluates it against the request method and path, and returns 403 Forbidden when the policy denies access.

Example:

api.New(api.WithAuthz(enforcer))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithAuthz(nil)
}()
coretest.Println("done")
Output:
done

func WithBearerAuth

func WithBearerAuth(token string) Option

WithBearerAuth adds bearer token authentication middleware. Requests to /health and the Swagger UI path are exempt.

Example:

api.New(api.WithBearerAuth("secret"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithBearerAuth("")
}()
coretest.Println("done")
Output:
done

func WithBrotli

func WithBrotli(level ...int) Option

WithBrotli adds Brotli response compression middleware using andybalholm/brotli. An optional compression level may be supplied (e.g. BrotliBestSpeed, BrotliBestCompression). If omitted, BrotliDefaultCompression is used.

Example:

api.New(api.WithBrotli())
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithBrotli()
}()
coretest.Println("done")
Output:
done

func WithCORS

func WithCORS(allowOrigins ...string) Option

WithCORS configures Cross-Origin Resource Sharing via gin-contrib/cors. Pass "*" to allow all origins, or supply specific origin URLs. Standard methods (GET, POST, PUT, PATCH, DELETE, OPTIONS) and common headers (Authorization, Content-Type, X-Request-ID) are permitted.

Example:

api.New(api.WithCORS("*"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithCORS()
}()
coretest.Println("done")
Output:
done

func WithCache

func WithCache(ttl time.Duration, maxEntries ...int) Option

WithCache adds in-memory response caching middleware for GET requests. Successful (2xx) GET responses are cached for the given TTL and served with an X-Cache: HIT header on subsequent requests. Non-GET methods and error responses pass through uncached.

Optional integer limits enable LRU eviction:

  • maxEntries limits the number of cached responses
  • maxBytes limits the approximate total cached payload size

At least one limit must be positive; when called with only a TTL the entry cap defaults to cacheDefaultMaxEntries (1 000) to prevent unbounded growth. A non-positive TTL disables the middleware entirely.

Example:

engine, _ := api.New(api.WithCache(5*time.Minute, 100, 10<<20))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithCache(0)
}()
coretest.Println("done")
Output:
done

func WithCacheLimits

func WithCacheLimits(ttl time.Duration, maxEntries, maxBytes int) Option

WithCacheLimits adds in-memory response caching middleware for GET requests with explicit entry and payload-size bounds.

This is the clearer form of WithCache when call sites want to make the eviction policy self-documenting.

Example:

engine, _ := api.New(api.WithCacheLimits(5*time.Minute, 100, 10<<20))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithCacheLimits(0, 0, 0)
}()
coretest.Println("done")
Output:
done

func WithChatCompletions

func WithChatCompletions(resolver *ModelResolver) Option

WithChatCompletions mounts an OpenAI-compatible POST /v1/chat/completions endpoint backed by the given ModelResolver. The resolver maps model names to loaded inference.TextModel instances (see chat_completions.go).

Use WithChatCompletionsPath to override the default "/v1/chat/completions" mount point. The endpoint streams Server-Sent Events when the request body sets "stream": true, and otherwise returns a single JSON response that mirrors OpenAI's chat completion payload.

Example:

resolver := api.NewModelResolver()
engine, _ := api.New(api.WithChatCompletions(resolver))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithChatCompletions(nil)
}()
coretest.Println("done")
Output:
done

func WithChatCompletionsPath

func WithChatCompletionsPath(path string) Option

WithChatCompletionsPath sets a custom URL path for the chat completions endpoint. The default path is "/v1/chat/completions".

Example:

api.New(api.WithChatCompletionsPath("/api/v1/chat/completions"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithChatCompletionsPath("")
}()
coretest.Println("done")
Output:
done

func WithExpvar

func WithExpvar() Option

WithExpvar enables the Go runtime metrics endpoint at /debug/vars. The endpoint serves JSON containing memstats, cmdline, and any custom expvar variables registered by the application. Powered by gin-contrib/expvar wrapping Go's standard expvar.Handler().

WARNING: expvar exposes runtime internals (memory allocation, goroutine counts, command-line arguments) and should only be enabled in development or behind authentication in production.

Example:

api.New(api.WithExpvar())
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithExpvar()
}()
coretest.Println("done")
Output:
done

func WithGraphQL

func WithGraphQL(schema graphql.ExecutableSchema, opts ...GraphQLOption) Option

WithGraphQL mounts a GraphQL endpoint serving the given gqlgen ExecutableSchema. By default the endpoint is mounted at "/graphql". Use GraphQLOption helpers to enable the playground UI or customise the path:

api.New(
    api.WithGraphQL(schema, api.WithPlayground(), api.WithGraphQLPath("/gql")),
)

Example:

engine, _ := api.New(api.WithGraphQL(schema))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithGraphQL(nil)
}()
coretest.Println("done")
Output:
done

func WithGzip

func WithGzip(level ...int) Option

WithGzip adds gzip response compression middleware via gin-contrib/gzip. An optional compression level may be supplied (e.g. gzip.BestSpeed, gzip.BestCompression). If omitted, gzip.DefaultCompression is used.

Example:

api.New(api.WithGzip())
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithGzip()
}()
coretest.Println("done")
Output:
done

func WithHTTP3

func WithHTTP3(addr string) Option

WithHTTP3 enables HTTP/3 advertisement and configures the QUIC listen address used by ServeH3. Pass an empty address to reuse the main HTTP address at serve time.

HTTP/3 requires TLS. ServeH3 returns ErrHTTP3TLSRequired when called without a TLS configuration.

Example:

api.New(api.WithHTTP3(":8443"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithHTTP3("")
}()
coretest.Println("done")
Output:
done

func WithHTTPSign

func WithHTTPSign(secrets httpsign.Secrets, opts ...httpsign.Option) Option

WithHTTPSign adds HTTP signature verification middleware via gin-contrib/httpsign. Incoming requests must carry a valid cryptographic signature in the Authorization or Signature header as defined by the HTTP Signatures specification (draft-cavage-http-signatures).

The caller provides a key store mapping key IDs to secrets (each pairing a shared key with a signing algorithm). Optional httpsign.Option values may configure required headers or custom validators; sensible defaults apply when omitted (date, digest, and request-target headers are required; date and digest validators are enabled).

Requests with a missing, malformed, or invalid signature are rejected with 401 Unauthorised or 400 Bad Request.

Example:

api.New(api.WithHTTPSign(secrets))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithHTTPSign(nil)
}()
coretest.Println("done")
Output:
done

func WithI18n

func WithI18n(cfg ...I18nConfig) Option

WithI18n adds Accept-Language header parsing and locale detection middleware. The middleware uses golang.org/x/text/language for RFC 5646 language matching with quality weighting support. The detected locale is stored in the Gin context and can be retrieved by handlers via GetLocale().

Example:

api.New(api.WithI18n(api.I18nConfig{Supported: []string{"en", "fr"}}))

If messages are configured, handlers can look up localised strings via GetMessage(). This is a lightweight bridge — the go-i18n grammar engine can replace the message map later.

Example (I18n)
func() {
	defer func() { _ = recover() }()
	_ = WithI18n()
}()
coretest.Println("done")
Output:
done

func WithLocation

func WithLocation() Option

WithLocation adds reverse proxy header detection middleware via gin-contrib/location. It inspects X-Forwarded-Proto and X-Forwarded-Host headers to determine the original scheme and host when the server runs behind a TLS-terminating reverse proxy such as Traefik.

After this middleware runs, handlers can call location.Get(c) to retrieve a *url.URL with the detected scheme, host, and base path.

Example:

engine, _ := api.New(api.WithLocation())
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithLocation()
}()
coretest.Println("done")
Output:
done

func WithMiddleware

func WithMiddleware(mw ...gin.HandlerFunc) Option

WithMiddleware appends arbitrary Gin middleware to the engine.

Example:

api.New(api.WithMiddleware(loggingMiddleware))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithMiddleware()
}()
coretest.Println("done")
Output:
done

func WithOpenAPISpec

func WithOpenAPISpec() Option

WithOpenAPISpec mounts a standalone JSON document endpoint at "/v1/openapi.json" (RFC.endpoints.md — "GET /v1/openapi.json"). The generated spec mirrors the document surfaced by the Swagger UI but is served application/json directly so SDK generators and ToolBridge consumers can fetch it without loading the UI bundle.

Example:

engine, _ := api.New(api.WithOpenAPISpec())
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithOpenAPISpec()
}()
coretest.Println("done")
Output:
done

func WithOpenAPISpecPath

func WithOpenAPISpecPath(path string) Option

WithOpenAPISpecPath sets a custom URL path for the standalone OpenAPI JSON endpoint. An empty string falls back to the RFC default "/v1/openapi.json". The override also enables the endpoint so callers can configure the URL without an additional WithOpenAPISpec() call.

Example:

api.New(api.WithOpenAPISpecPath("/api/v1/openapi.json"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithOpenAPISpecPath("")
}()
coretest.Println("done")
Output:
done

func WithPprof

func WithPprof() Option

WithPprof enables Go runtime profiling endpoints at /debug/pprof/. The standard pprof handlers (index, cmdline, profile, symbol, trace, allocs, block, goroutine, heap, mutex, threadcreate) are registered via gin-contrib/pprof.

WARNING: pprof exposes sensitive runtime data and should only be enabled in development or behind authentication in production.

Example:

api.New(api.WithPprof())
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithPprof()
}()
coretest.Println("done")
Output:
done

func WithRateLimit

func WithRateLimit(limit int) Option

WithRateLimit adds token-bucket rate limiting middleware. Requests are bucketed by API key or bearer token when present, and otherwise by client IP. Passing requests are annotated with X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. Requests exceeding the configured limit are rejected with 429 Too Many Requests, Retry-After, and the standard Fail() error envelope. A zero or negative limit disables rate limiting.

Example:

engine, _ := api.New(api.WithRateLimit(100))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithRateLimit(0)
}()
coretest.Println("done")
Output:
done

func WithRequestID

func WithRequestID() Option

WithRequestID adds middleware that assigns an X-Request-ID to every response. Client-provided IDs are preserved; otherwise a random hex ID is generated.

Example:

api.New(api.WithRequestID())
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithRequestID()
}()
coretest.Println("done")
Output:
done

func WithResponseMeta

func WithResponseMeta() Option

WithResponseMeta attaches request metadata to JSON envelope responses. It preserves any existing pagination metadata and merges in request_id and duration when available from the request context. Combine it with WithRequestID() to populate both fields automatically.

Example:

api.New(api.WithRequestID(), api.WithResponseMeta())
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithResponseMeta()
}()
coretest.Println("done")
Output:
done

func WithSDKGen

func WithSDKGen() Option

WithSDKGen mounts POST /v1/sdk/generate. The endpoint exposes the RFC SDK generation contract and currently returns 501 until an artifact backend is configured around SDKGenerator.

Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSDKGen()
}()
coretest.Println("done")
Output:
done

func WithSSE

func WithSSE(broker *SSEBroker) Option

WithSSE registers a Server-Sent Events broker at the configured path. By default the endpoint is mounted at GET /events; use WithSSEPath to customise the route. Clients receive a streaming text/event-stream response and the broker manages client connections and broadcasts events published via its Publish method.

Example:

broker := api.NewSSEBroker()
engine, _ := api.New(api.WithSSE(broker))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSSE(nil)
}()
coretest.Println("done")
Output:
done

func WithSSEPath

func WithSSEPath(path string) Option

WithSSEPath sets a custom URL path for the SSE endpoint. The default path is "/events".

Example:

api.New(api.WithSSEPath("/stream"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSSEPath("")
}()
coretest.Println("done")
Output:
done

func WithSecure

func WithSecure() Option

WithSecure adds security headers middleware via gin-contrib/secure. Default policy sets HSTS (1 year, includeSubDomains), X-Frame-Options DENY, X-Content-Type-Options nosniff, and Referrer-Policy strict-origin-when-cross-origin. SSL redirect is not enabled so the middleware works behind a reverse proxy that terminates TLS.

Example:

api.New(api.WithSecure())
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSecure()
}()
coretest.Println("done")
Output:
done

func WithSessions

func WithSessions(name string, secret []byte) Option

WithSessions adds server-side session management middleware via gin-contrib/sessions using a cookie-based store. The name parameter sets the session cookie name (e.g. "session") and secret is the key used for cookie signing and encryption.

Example:

api.New(api.WithSessions("session", []byte("secret")))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSessions("", nil)
}()
coretest.Println("done")
Output:
done

func WithSlog

func WithSlog(logger *slog.Logger) Option

WithSlog adds structured request logging middleware via gin-contrib/slog. Each request is logged with method, path, status code, latency, and client IP. If logger is nil, slog.Default() is used.

Example:

api.New(api.WithSlog(nil))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSlog(nil)
}()
coretest.Println("done")
Output:
done

func WithStatic

func WithStatic(urlPrefix, root string) Option

WithStatic serves static files from the given root directory at urlPrefix. Directory listing is disabled; only individual files are served. Internally this uses gin-contrib/static as Gin middleware.

Example:

api.New(api.WithStatic("/assets", "./public"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithStatic("", "")
}()
coretest.Println("done")
Output:
done

func WithSunset

func WithSunset(sunsetDate, replacement string) Option

WithSunset adds deprecation headers to every response. The middleware appends Deprecation, optional Sunset, optional Link, and X-API-Warn headers without clobbering any existing header values. Use it to deprecate an entire route group or API version.

Example:

api.New(api.WithSunset("2026-12-31", "https://api.example.com/v2"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSunset("", "")
}()
coretest.Println("done")
Output:
done

func WithSwagger

func WithSwagger(title, description, version string) Option

WithSwagger enables the Swagger UI at /swagger/ by default. The title, description, and version populate the OpenAPI info block. Use WithSwaggerSummary() to set the optional info.summary field.

Example:

api.New(api.WithSwagger("Service", "Public API", "1.0.0"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSwagger("", "", "")
}()
coretest.Println("done")
Output:
done

func WithSwaggerContact

func WithSwaggerContact(name, url, email string) Option

WithSwaggerContact adds contact metadata to the generated Swagger spec. Empty fields are ignored. Multiple calls replace the previous contact data.

Example:

api.WithSwaggerContact("API Support", "https://example.com/support", "support@example.com")
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSwaggerContact("", "", "")
}()
coretest.Println("done")
Output:
done

func WithSwaggerExternalDocs

func WithSwaggerExternalDocs(description, url string) Option

WithSwaggerExternalDocs adds top-level external documentation metadata to the generated Swagger spec. Empty URLs are ignored; the description is optional.

Example:

api.WithSwaggerExternalDocs("Developer guide", "https://example.com/docs")
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSwaggerExternalDocs("", "")
}()
coretest.Println("done")
Output:
done

func WithSwaggerLicense

func WithSwaggerLicense(name, url string) Option

WithSwaggerLicense adds licence metadata to the generated Swagger spec. Pass both a name and URL to populate the OpenAPI info block consistently.

Example:

api.WithSwaggerLicense("EUPL-1.2", "https://eupl.eu/1.2/en/")
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSwaggerLicense("", "")
}()
coretest.Println("done")
Output:
done

func WithSwaggerPath

func WithSwaggerPath(path string) Option

WithSwaggerPath sets a custom URL path for the Swagger UI. The default path is "/swagger".

Example:

api.New(api.WithSwaggerPath("/docs"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSwaggerPath("")
}()
coretest.Println("done")
Output:
done

func WithSwaggerSecuritySchemes

func WithSwaggerSecuritySchemes(schemes map[string]any) Option

WithSwaggerSecuritySchemes merges custom OpenAPI security schemes into the generated Swagger spec. Existing schemes are preserved unless the new map defines the same key, in which case the later definition wins.

Example:

api.WithSwaggerSecuritySchemes(map[string]any{
	"apiKeyAuth": map[string]any{
		"type": "apiKey",
		"in":   "header",
		"name": "X-API-Key",
	},
})
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSwaggerSecuritySchemes(nil)
}()
coretest.Println("done")
Output:
done

func WithSwaggerServers

func WithSwaggerServers(servers ...string) Option

WithSwaggerServers adds OpenAPI server metadata to the generated Swagger spec. Empty strings are ignored. Multiple calls append and normalise the combined server list so callers can compose metadata across options.

Example:

api.WithSwaggerServers("https://api.example.com", "https://docs.example.com")
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSwaggerServers()
}()
coretest.Println("done")
Output:
done

func WithSwaggerSummary

func WithSwaggerSummary(summary string) Option

WithSwaggerSummary adds the OpenAPI info.summary field to generated specs.

Example:

api.WithSwaggerSummary("Service overview")
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSwaggerSummary("")
}()
coretest.Println("done")
Output:
done

func WithSwaggerTermsOfService

func WithSwaggerTermsOfService(url string) Option

WithSwaggerTermsOfService adds the terms of service URL to the generated Swagger spec. Empty strings are ignored.

Example:

api.WithSwaggerTermsOfService("https://example.com/terms")
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithSwaggerTermsOfService("")
}()
coretest.Println("done")
Output:
done

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout adds per-request timeout middleware via gin-contrib/timeout. If a handler exceeds the given duration, the request is aborted with a 504 Gateway Timeout carrying the standard error envelope:

{"success":false,"error":{"code":"timeout","message":"Request timed out"}}

A zero or negative duration effectively disables the timeout (the handler runs without a deadline) — this is safe and will not panic.

Example:

api.New(api.WithTimeout(5 * time.Second))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithTimeout(0)
}()
coretest.Println("done")
Output:
done

func WithTracing

func WithTracing(serviceName string, opts ...otelgin.Option) Option

WithTracing adds OpenTelemetry distributed tracing middleware via otelgin. Each incoming request produces a span tagged with the HTTP method, route, and status code. Trace context is propagated using W3C traceparent headers.

The serviceName identifies this service in distributed traces. If a TracerProvider has not been configured globally via otel.SetTracerProvider, the middleware uses the global default (which is a no-op until set).

Typical setup in main:

tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter))
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.TraceContext{})

engine, _ := api.New(api.WithTracing("my-service"))

Example:

api.New(api.WithTracing("my-service"))
Example (Tracing)
func() {
	defer func() { _ = recover() }()
	_ = WithTracing("")
}()
coretest.Println("done")
Output:
done

func WithWSHandler

func WithWSHandler(h http.Handler) Option

WithWSHandler registers a WebSocket handler at GET /ws. Use WithWSPath to customise the route before mounting the handler. Typically this wraps a go-ws Hub.Handler().

Example:

api.New(api.WithWSHandler(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithWSHandler(nil)
}()
coretest.Println("done")
Output:
done

func WithWSPath

func WithWSPath(path string) Option

WithWSPath sets a custom URL path for the WebSocket endpoint. The default path is "/ws".

Example:

api.New(api.WithWSPath("/socket"))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithWSPath("")
}()
coretest.Println("done")
Output:
done

func WithWebSocket

func WithWebSocket(h gin.HandlerFunc) Option

WithWebSocket registers a Gin-native WebSocket handler at GET /ws.

This is the gin-handler form of WithWSHandler. The handler receives the request via *gin.Context and is responsible for performing the upgrade (typically with gorilla/websocket) and managing the message loop. Use WithWSPath to customise the route before mounting the handler.

Example:

api.New(api.WithWebSocket(func(c *gin.Context) {
    // upgrade and handle messages
}))
Example (Options)
func() {
	defer func() { _ = recover() }()
	_ = WithWebSocket(nil)
}()
coretest.Println("done")
Output:
done

type ParameterDescription

type ParameterDescription struct {
	Name        string         // Parameter name.
	In          string         // Parameter location: path, query, header, or cookie.
	Description string         // Human-readable parameter description.
	Required    bool           // Whether the parameter is required.
	Deprecated  bool           // Whether the parameter is deprecated.
	Schema      map[string]any // JSON Schema for the parameter value.
	Example     any            // Optional example value.
}

ParameterDescription describes an OpenAPI parameter for a route.

Example:

param := api.ParameterDescription{
	Name:        "id",
	In:          `path`,
	Description: "User identifier",
	Required:    true,
	Schema:      map[string]any{"type": "string"},
	Example:     "usr_123",
}

type RenderHints

type RenderHints struct {
	Kind    string       `json:"kind,omitempty"`    // "form" | "table" | "modal" | "grid"
	Fields  []FieldHint  `json:"fields,omitempty"`  // Form fields with validation hints.
	Actions []ActionHint `json:"actions,omitempty"` // Inline action buttons.
}

RenderHints describes how a UI may present an operation.

type Renderable

type Renderable interface {
	// Render returns UI hints for the operation.
	Render() RenderHints
}

Renderable allows a route handler or controller to expose UI rendering hints that spec consumers can surface via vendor extensions.

Example:

var r api.Renderable = &myHandler{}

type Response

type Response[T any] struct {
	Success bool   `json:"success"`
	Data    T      `json:"data,omitempty"`
	Error   *Error `json:"error,omitempty"`
	Meta    *Meta  `json:"meta,omitempty"`
}

Response is the standard envelope for all API responses.

Example:

resp := api.OK(map[string]any{"id": 42})
resp.Success // true

func AttachRequestMeta

func AttachRequestMeta[T any](c *gin.Context, resp Response[T]) Response[T]

AttachRequestMeta merges request metadata into an existing response envelope. Existing pagination metadata is preserved; request_id and duration are added when available from the Gin context.

Example:

resp = api.AttachRequestMeta(c, resp)
Example (Response)
func() {
	defer func() { _ = recover() }()
	_ = AttachRequestMeta[any](nil, Response[any]{})
}()
coretest.Println("done")
Output:
done

func Fail

func Fail(code, message string) Response[any]

Fail creates an error response with the given code and message.

Example:

c.JSON(http.StatusBadRequest, api.Fail("invalid_input", "Name is required"))
Example (Response)
func() {
	defer func() { _ = recover() }()
	_ = Fail("", "")
}()
coretest.Println("done")
Output:
done

func FailWithDetails

func FailWithDetails(code, message string, details any) Response[any]

FailWithDetails creates an error response with additional detail payload.

Example:

c.JSON(http.StatusBadRequest, api.FailWithDetails("invalid_input", "Name is required", map[string]any{"field": "name"}))
Example (Response)
func() {
	defer func() { _ = recover() }()
	_ = FailWithDetails("", "", nil)
}()
coretest.Println("done")
Output:
done

func OK

func OK[T any](data T) Response[T]

OK wraps data in a successful response envelope.

Example:

c.JSON(http.StatusOK, api.OK(map[string]any{"name": "status"}))
Example (Response)
func() {
	defer func() { _ = recover() }()
	_ = OK[any](nil)
}()
coretest.Println("done")
Output:
done

func Paginated

func Paginated[T any](data T, page, perPage, total int) Response[T]

Paginated wraps data in a successful response with pagination metadata.

Example:

c.JSON(http.StatusOK, api.Paginated(items, 2, 50, 200))
Example (Response)
func() {
	defer func() { _ = recover() }()
	_ = Paginated[any](nil, 0, 0, 0)
}()
coretest.Println("done")
Output:
done

type RouteDescription

type RouteDescription struct {
	Method      string   // HTTP method: GET, POST, PUT, DELETE, PATCH
	Path        string   // Path relative to BasePath, e.g. "/generate"
	Summary     string   // Short summary
	Description string   // Long description
	Tags        []string // OpenAPI tags for grouping
	// Handler optionally points at the route handler/controller that implements
	// Describable and/or Renderable. RegisterRoutes still owns actual Gin
	// wiring; this field is metadata-only for spec generation.
	Handler any
	// CacheControl hints the framework that successful responses for this
	// operation should advertise the given Cache-Control policy in docs.
	CacheControl string
	// Hidden omits the route from generated documentation.
	Hidden bool
	// Deprecated marks the operation as deprecated in OpenAPI.
	Deprecated bool
	// SunsetDate marks when a deprecated operation will be removed.
	// Use YYYY-MM-DD or an RFC 7231 HTTP date string.
	SunsetDate string
	// ReplacementURL points to the successor endpoint URL, when known.
	// Replacement is kept as a legacy alias for existing call sites.
	ReplacementURL string
	Replacement    string
	// NoticeURL points to a detailed deprecation notice or migration guide,
	// surfaced as the API-Deprecation-Notice-URL response header per spec §8.
	NoticeURL string
	// StatusCode is the documented 2xx success status code.
	// Zero defaults to 200.
	StatusCode int
	// Security overrides the default bearerAuth requirement when non-nil.
	// Use an empty, non-nil slice to mark the route as public.
	Security        []map[string][]string
	Parameters      []ParameterDescription
	RequestBody     map[string]any // JSON Schema for request body (nil for GET)
	RequestExample  any            // Optional example payload for the request body.
	Response        map[string]any // JSON Schema for success response data
	ResponseExample any            // Optional example payload for the success response.
	ResponseHeaders map[string]string
	// TransformerIn optionally remaps the external request DTO into the
	// handler-facing DTO before RegisterRoutes' handler reads the request body.
	// Supply a TransformerIn[I, O] or a slice of transformers to compose a
	// pipeline.
	TransformerIn any
	// TransformerOut optionally remaps the handler-facing response DTO into the
	// external response DTO inside the standard OK() envelope.
	// Supply a TransformerOut[I, O] or a slice of transformers to compose a
	// pipeline.
	TransformerOut any
}

RouteDescription describes a single endpoint for OpenAPI generation.

Example:

rd := api.RouteDescription{
	Method:      "POST",
	Path:        "/users",
	Summary:     "Create a user",
	Description: "Creates a new user account.",
	Tags:        []string{"users"},
	StatusCode:  201,
	RequestBody: map[string]any{"type": "object"},
	Response:    map[string]any{"type": "object"},
}

type RouteGroup

type RouteGroup interface {
	// Name returns a human-readable identifier for the group.
	Name() string

	// BasePath returns the URL prefix for all routes in this group.
	BasePath() string

	// RegisterRoutes mounts handlers onto the provided router group.
	RegisterRoutes(rg *gin.RouterGroup)
}

RouteGroup registers API routes onto a Gin router group. Subsystems implement this interface to declare their endpoints.

Example:

var g api.RouteGroup = &myGroup{}

func RegisteredSpecGroups

func RegisteredSpecGroups() []RouteGroup

RegisteredSpecGroups returns a copy of the route groups registered for CLI-generated OpenAPI documents.

Example:

groups := api.RegisteredSpecGroups()
Example (SpecRegistry)
func() {
	defer func() { _ = recover() }()
	_ = RegisteredSpecGroups()
}()
coretest.Println("done")
Output:
done

type RuntimeConfig

type RuntimeConfig struct {
	Swagger   SwaggerConfig
	Transport TransportConfig
	GraphQL   GraphQLConfig
	Cache     CacheConfig
	I18n      I18nConfig
	Authentik AuthentikConfig
}

RuntimeConfig captures the engine's current runtime-facing configuration in a single snapshot.

It groups the existing Swagger, transport, GraphQL, cache, and i18n snapshots so callers can inspect the active engine surface without joining multiple method results themselves.

Example:

cfg := engine.RuntimeConfig()

type SDKGenRequest

type SDKGenRequest struct {
	Language string `json:"language"`
}

SDKGenRequest is the request body for POST /v1/sdk/generate.

type SDKGenResponse

type SDKGenResponse struct {
	URL    string `json:"url"`
	SHA256 string `json:"sha256"`
}

SDKGenResponse is the successful response body for generated SDK artifacts.

type SDKGenerator

type SDKGenerator struct {
	// SpecPath is the path to the OpenAPI spec file (JSON or YAML).
	SpecPath string

	// OutputDir is the base directory for generated SDK output.
	OutputDir string

	// PackageName is the name used for the generated package/module.
	PackageName string
}

SDKGenerator wraps openapi-generator-cli for SDK generation.

Example:

gen := &api.SDKGenerator{SpecPath: "./openapi.yaml", OutputDir: "./sdk", PackageName: "service"}

func (*SDKGenerator) Available

func (g *SDKGenerator) Available() bool

Available checks if openapi-generator-cli is installed and accessible.

Example:

if !gen.Available() {
	t.Fatal("openapi-generator-cli is required")
}
Example (Codegen)
func() {
	defer func() { _ = recover() }()
	var subject *SDKGenerator
	_ = subject.Available()
}()
coretest.Println("done")
Output:
done

func (*SDKGenerator) Generate

func (g *SDKGenerator) Generate(ctx context.Context, language string) (
	_ error,
)

Generate creates an SDK for the given language using openapi-generator-cli. The language must be one of the supported languages returned by SupportedLanguages().

Example:

err := gen.Generate(context.Background(), "go")
Example (Codegen)
func() {
	defer func() { _ = recover() }()
	var subject *SDKGenerator
	_ = subject.Generate(nil, "")
}()
coretest.Println("done")
Output:
done

type SSEBroker

type SSEBroker struct {
	// contains filtered or unexported fields
}

SSEBroker manages Server-Sent Events connections and broadcasts events to subscribed clients. Clients connect via a GET endpoint and receive a streaming text/event-stream response. Each client may optionally subscribe to a specific channel via the ?channel= query parameter.

Example:

broker := api.NewSSEBroker()
engine.GET("/events", broker.Handler())

func NewSSEBroker

func NewSSEBroker() *SSEBroker

NewSSEBroker creates a ready-to-use SSE broker.

Example:

broker := api.NewSSEBroker()
Example (Sse)
func() {
	defer func() { _ = recover() }()
	_ = NewSSEBroker()
}()
coretest.Println("done")
Output:
done

func (*SSEBroker) ClientCount

func (b *SSEBroker) ClientCount() int

ClientCount returns the number of currently connected SSE clients.

Example:

n := broker.ClientCount()
Example (Sse)
func() {
	defer func() { _ = recover() }()
	var subject *SSEBroker
	_ = subject.ClientCount()
}()
coretest.Println("done")
Output:
done

func (*SSEBroker) Drain

func (b *SSEBroker) Drain()

Drain signals all connected clients to disconnect and waits for their handler goroutines to exit. Useful for graceful shutdown.

Example:

broker.Drain()
Example (Sse)
func() {
	defer func() { _ = recover() }()
	var subject *SSEBroker
	subject.Drain()
}()
coretest.Println("done")
Output:
done

func (*SSEBroker) Handler

func (b *SSEBroker) Handler() gin.HandlerFunc

Handler returns a Gin handler for the SSE endpoint. Clients connect with a GET request and receive events as text/event-stream. An optional ?channel=<name> query parameter subscribes the client to a specific channel.

Example:

engine.GET("/events", broker.Handler())
Example (Sse)
func() {
	defer func() { _ = recover() }()
	var subject *SSEBroker
	_ = subject.Handler()
}()
coretest.Println("done")
Output:
done

func (*SSEBroker) Publish

func (b *SSEBroker) Publish(channel, event string, data any)

Publish sends an event to all clients subscribed to the given channel. Clients subscribed to an empty channel (no ?channel= param) receive events on every channel. The data value is JSON-encoded before sending.

Example:

broker.Publish("system", "ready", map[string]any{"status": "ok"})
Example (Sse)
func() {
	defer func() { _ = recover() }()
	var subject *SSEBroker
	subject.Publish("", "", nil)
}()
coretest.Println("done")
Output:
done

type SSEClient

type SSEClient struct {
	URL    string
	Header http.Header
	Client *http.Client
}

SSEClient is a small client helper for consuming text/event-stream endpoints exposed by SSEBroker.

Example:

client := api.NewSSEClient("http://localhost:8080/events")
events, err := client.Events(ctx)

func NewSSEClient

func NewSSEClient(rawURL string, opts ...SSEClientOption) *SSEClient

NewSSEClient constructs an SSEClient with sensible defaults.

Example:

client := api.NewSSEClient("http://localhost:8080/events")
Example (TransportClient)
func() {
	defer func() { _ = recover() }()
	_ = NewSSEClient("")
}()
coretest.Println("done")
Output:
done

func (*SSEClient) Connect

func (c *SSEClient) Connect(ctx context.Context) (
	*http.Response,
	error,
)

Connect opens the SSE stream and returns the underlying HTTP response.

Example:

resp, err := client.Connect(ctx)
Example (TransportClient)
func() {
	defer func() { _ = recover() }()
	var subject *SSEClient
	_, _ = subject.Connect(nil)
}()
coretest.Println("done")
Output:
done

func (*SSEClient) Events

func (c *SSEClient) Events(ctx context.Context) (
	<-chan SSEEvent,
	error,
)

Events connects to the stream and returns a channel of parsed SSE events. The channel is closed when the stream ends or the context is cancelled.

Example:

events, err := client.Events(ctx)
if err != nil { ... }
for evt := range events { _ = evt }
Example (TransportClient)
func() {
	defer func() { _ = recover() }()
	var subject *SSEClient
	_, _ = subject.Events(nil)
}()
coretest.Println("done")
Output:
done

type SSEClientOption

type SSEClientOption func(*SSEClient)

SSEClientOption configures an SSEClient.

func WithSSEHTTPClient

func WithSSEHTTPClient(client *http.Client) SSEClientOption

WithSSEHTTPClient sets the HTTP client used to establish the SSE stream.

Example (TransportClient)
func() {
	defer func() { _ = recover() }()
	_ = WithSSEHTTPClient(nil)
}()
coretest.Println("done")
Output:
done

func WithSSEHeaders

func WithSSEHeaders(header http.Header) SSEClientOption

WithSSEHeaders adds request headers to the outbound SSE request.

Example (TransportClient)
func() {
	defer func() { _ = recover() }()
	_ = WithSSEHeaders(nil)
}()
coretest.Println("done")
Output:
done

type SSEEvent

type SSEEvent struct {
	ID    string
	Event string
	Data  string
	Retry time.Duration
}

SSEEvent is a parsed Server-Sent Events message.

Example:

for evt := range events {
    _ = evt
}

type SpecBuilder

type SpecBuilder struct {
	Title                   string
	Summary                 string
	Description             string
	Version                 string
	SwaggerEnabled          bool
	SwaggerPath             string
	GraphQLEnabled          bool
	GraphQLPath             string
	GraphQLPlayground       bool
	GraphQLPlaygroundPath   string
	WSPath                  string
	WSEnabled               bool
	SSEPath                 string
	SSEEnabled              bool
	TermsOfService          string
	ContactName             string
	ContactURL              string
	ContactEmail            string
	Servers                 []string
	LicenseName             string
	LicenseURL              string
	SecuritySchemes         map[string]any
	ExternalDocsDescription string
	ExternalDocsURL         string
	PprofEnabled            bool
	ExpvarEnabled           bool
	ChatCompletionsEnabled  bool
	ChatCompletionsPath     string
	OpenAPISpecEnabled      bool
	OpenAPISpecPath         string
	CacheEnabled            bool
	CacheTTL                string
	CacheMaxEntries         int
	CacheMaxBytes           int
	I18nDefaultLocale       string
	I18nSupportedLocales    []string
	AuthentikIssuer         string
	AuthentikClientID       string
	AuthentikTrustedProxy   bool
	AuthentikPublicPaths    []string
}

SpecBuilder constructs an OpenAPI 3.1 specification from registered RouteGroups. Title, Summary, Description, Version, and optional contact/licence/terms metadata populate the OpenAPI info block. Top-level external documentation metadata is also supported, along with additive extension fields that describe runtime transport, cache, i18n, and Authentik settings.

Example:

builder := &api.SpecBuilder{Title: "Service", Version: "1.0.0"}
spec, err := builder.Build(engine.Groups())

func (*SpecBuilder) Build

func (sb *SpecBuilder) Build(groups []RouteGroup) (
	[]byte,
	error,
)

Build generates the complete OpenAPI 3.1 JSON spec. Groups implementing DescribableGroup contribute endpoint documentation. Other groups are listed as tags only.

Example:

data, err := (&api.SpecBuilder{Title: "Service", Version: "1.0.0"}).Build(engine.Groups())
Example (Openapi)
func() {
	defer func() { _ = recover() }()
	var subject *SpecBuilder
	_, _ = subject.Build(nil)
}()
coretest.Println("done")
Output:
done

func (*SpecBuilder) BuildIter

func (sb *SpecBuilder) BuildIter(groups iter.Seq[RouteGroup]) (
	[]byte,
	error,
)

BuildIter generates the complete OpenAPI 3.1 JSON spec from a route-group iterator. The iterator is snapshotted before building so the result stays stable even if the source changes during rendering.

Example:

data, err := (&api.SpecBuilder{Title: "Service"}).BuildIter(api.RegisteredSpecGroupsIter())
Example (Openapi)
func() {
	defer func() { _ = recover() }()
	var subject *SpecBuilder
	_, _ = subject.BuildIter(nil)
}()
coretest.Println("done")
Output:
done

type StreamGroup

type StreamGroup interface {
	// Channels returns the list of channel names this group streams on.
	Channels() []string
}

StreamGroup optionally declares WebSocket channels a subsystem publishes to.

Example:

var sg api.StreamGroup = &myStreamGroup{}

type SunsetOption

type SunsetOption func(*sunsetConfig)

SunsetOption customises the behaviour of ApiSunsetWith. Use the supplied constructors (e.g. WithSunsetNoticeURL) to compose the desired metadata without breaking the simpler ApiSunset signature.

mw := api.ApiSunsetWith("2025-06-01", "/api/v2/users",
    api.WithSunsetNoticeURL("https://docs.example.com/deprecation/billing"),
)

func WithSunsetNoticeURL

func WithSunsetNoticeURL(url string) SunsetOption

WithSunsetNoticeURL adds the API-Deprecation-Notice-URL header documented in spec §8 to every response. The URL should point to a human-readable migration guide for the deprecated endpoint.

api.ApiSunsetWith("2026-04-30", "POST /api/v2/billing/invoices",
    api.WithSunsetNoticeURL("https://docs.api.dappco.re/deprecation/billing"),
)
Example (Sunset)
func() {
	defer func() { _ = recover() }()
	_ = WithSunsetNoticeURL("")
}()
coretest.Println("done")
Output:
done

type SwaggerConfig

type SwaggerConfig struct {
	Enabled                 bool
	Path                    string
	Title                   string
	Summary                 string
	Description             string
	Version                 string
	TermsOfService          string
	ContactName             string
	ContactURL              string
	ContactEmail            string
	Servers                 []string
	LicenseName             string
	LicenseURL              string
	SecuritySchemes         map[string]any
	ExternalDocsDescription string
	ExternalDocsURL         string
}

SwaggerConfig captures the configured Swagger/OpenAPI metadata for an Engine.

It is intentionally small and serialisable so callers can inspect the active documentation surface without rebuilding an OpenAPI document.

Example:

cfg := api.SwaggerConfig{Title: "Service", Summary: "Public API"}

type ThinkingExtractor

type ThinkingExtractor struct {
	// contains filtered or unexported fields
}

ThinkingExtractor separates thinking channel content from response text. Applied as a post-processing step on the token stream.

extractor := NewThinkingExtractor()
for tok := range model.Chat(ctx, messages) {
	extractor.Process(tok)
}
response := extractor.Content()   // User-facing text
thinking := extractor.Thinking()  // Internal reasoning (may be nil)

func NewThinkingExtractor

func NewThinkingExtractor() *ThinkingExtractor

NewThinkingExtractor constructs a ThinkingExtractor that starts on the "assistant" channel. Tokens are routed to Content() until a "<|channel>thought" marker switches the stream to the thinking channel (and similarly back).

extractor := api.NewThinkingExtractor()
Example (ChatCompletions)
func() {
	defer func() { _ = recover() }()
	_ = NewThinkingExtractor()
}()
coretest.Println("done")
Output:
done

func (*ThinkingExtractor) Content

func (te *ThinkingExtractor) Content() string

Content returns all text accumulated on the user-facing "assistant" channel so far. Safe to call on a nil receiver (returns "").

text := extractor.Content()
Example (ChatCompletions)
func() {
	defer func() { _ = recover() }()
	var subject *ThinkingExtractor
	_ = subject.Content()
}()
coretest.Println("done")
Output:
done

func (*ThinkingExtractor) Process

func (te *ThinkingExtractor) Process(token inference.Token)

Process feeds a single generated token into the extractor. Tokens are appended to the current channel buffer (content or thought), switching on the "<|channel>NAME" marker. Non-streaming handlers call Process in a loop and then read Content and Thinking when generation completes.

for tok := range model.Chat(ctx, messages) {
    extractor.Process(tok)
}
Example (ChatCompletions)
func() {
	defer func() { _ = recover() }()
	var subject *ThinkingExtractor
	subject.Process(inference.Token{})
}()
coretest.Println("done")
Output:
done

func (*ThinkingExtractor) Thinking

func (te *ThinkingExtractor) Thinking() *string

Thinking returns all text accumulated on the internal "thought" channel so far or nil when no thinking tokens were produced. Safe to call on a nil receiver.

if thinking := extractor.Thinking(); thinking != nil {
    response.Thought = thinking
}
Example (ChatCompletions)
func() {
	defer func() { _ = recover() }()
	var subject *ThinkingExtractor
	_ = subject.Thinking()
}()
coretest.Println("done")
Output:
done

type ToolBridge

type ToolBridge struct {
	// contains filtered or unexported fields
}

ToolBridge converts tool descriptors into REST endpoints and OpenAPI paths. It implements both RouteGroup and DescribableGroup.

Example:

bridge := api.NewToolBridge("/mcp")

func NewToolBridge

func NewToolBridge(basePath string) *ToolBridge

NewToolBridge creates a bridge that mounts tool endpoints at basePath.

Example:

bridge := api.NewToolBridge("/mcp")
Example (Bridge)
func() {
	defer func() { _ = recover() }()
	_ = NewToolBridge("")
}()
coretest.Println("done")
Output:
done

func (*ToolBridge) Add

func (b *ToolBridge) Add(desc ToolDescriptor, handler gin.HandlerFunc)

Add registers a tool with its HTTP handler.

Example:

bridge.Add(api.ToolDescriptor{Name: "ping", Description: "Ping the service"}, handler)
Example (Bridge)
func() {
	defer func() { _ = recover() }()
	var subject *ToolBridge
	subject.Add(ToolDescriptor{}, nil)
}()
coretest.Println("done")
Output:
done

func (*ToolBridge) BasePath

func (b *ToolBridge) BasePath() string

BasePath returns the URL prefix for all tool endpoints.

Example:

path := bridge.BasePath()
Example (Bridge)
func() {
	defer func() { _ = recover() }()
	var subject *ToolBridge
	_ = subject.BasePath()
}()
coretest.Println("done")
Output:
done

func (*ToolBridge) Describe

func (b *ToolBridge) Describe() []RouteDescription

Describe returns OpenAPI route descriptions for all registered tools plus a GET entry describing the tool listing endpoint at the bridge's base path.

Example:

descs := bridge.Describe()
Example (Bridge)
func() {
	defer func() { _ = recover() }()
	var subject *ToolBridge
	_ = subject.Describe()
}()
coretest.Println("done")
Output:
done

func (*ToolBridge) DescribeIter

func (b *ToolBridge) DescribeIter() iter.Seq[RouteDescription]

DescribeIter returns an iterator over OpenAPI route descriptions for all registered tools plus a leading GET entry for the tool listing endpoint.

Example:

for rd := range bridge.DescribeIter() {
	_ = rd
}
Example (Bridge)
func() {
	defer func() { _ = recover() }()
	var subject *ToolBridge
	_ = subject.DescribeIter()
}()
coretest.Println("done")
Output:
done

func (*ToolBridge) Name

func (b *ToolBridge) Name() string

Name returns the bridge identifier.

Example:

name := bridge.Name()
Example (Bridge)
func() {
	defer func() { _ = recover() }()
	var subject *ToolBridge
	_ = subject.Name()
}()
coretest.Println("done")
Output:
done

func (*ToolBridge) RegisterRoutes

func (b *ToolBridge) RegisterRoutes(rg *gin.RouterGroup)

RegisterRoutes mounts GET / (tool listing) and POST /{tool_name} for each registered tool. The listing endpoint returns a JSON envelope containing the registered tool descriptors and mirrors RFC.endpoints.md §"ToolBridge" so clients can discover every tool exposed on the bridge in a single call.

Example:

bridge.RegisterRoutes(rg)
// GET  /{basePath}/        -> tool catalogue
// POST /{basePath}/{name}  -> dispatch tool
Example (Bridge)
func() {
	defer func() { _ = recover() }()
	var subject *ToolBridge
	subject.RegisterRoutes(nil)
}()
coretest.Println("done")
Output:
done

func (*ToolBridge) Tools

func (b *ToolBridge) Tools() []ToolDescriptor

Tools returns all registered tool descriptors.

Example:

descs := bridge.Tools()
Example (Bridge)
func() {
	defer func() { _ = recover() }()
	var subject *ToolBridge
	_ = subject.Tools()
}()
coretest.Println("done")
Output:
done

func (*ToolBridge) ToolsIter

func (b *ToolBridge) ToolsIter() iter.Seq[ToolDescriptor]

ToolsIter returns an iterator over all registered tool descriptors.

Example:

for desc := range bridge.ToolsIter() {
	_ = desc
}
Example (Bridge)
func() {
	defer func() { _ = recover() }()
	var subject *ToolBridge
	_ = subject.ToolsIter()
}()
coretest.Println("done")
Output:
done

type ToolDescriptor

type ToolDescriptor struct {
	Name         string         // Tool name, e.g. "file_read" (becomes POST path segment)
	Description  string         // Human-readable description
	Group        string         // OpenAPI tag group, e.g. "files"
	InputSchema  map[string]any // JSON Schema for request body
	OutputSchema map[string]any // JSON Schema for response data (optional)
	// TransformerIn remaps the external request DTO into the handler-facing
	// DTO before the tool handler reads the request body.
	TransformerIn any
	// TransformerOut remaps the handler-facing response DTO into the external
	// response DTO inside the standard OK() envelope.
	TransformerOut any
}

ToolDescriptor describes a tool that can be exposed as a REST endpoint.

Example:

desc := api.ToolDescriptor{Name: "ping", Description: "Ping the service"}

type TransformerIn

type TransformerIn[I, O any] interface {
	TransformIn(*gin.Context, I) (O, error)
}

TransformerIn remaps an external request DTO into the handler-facing DTO. Implementations may also validate and normalise the inbound payload.

Example:

type externalCreateUser struct {
	FullName string `json:"full_name"`
}
type createUser struct {
	Name string `json:"name"`
}
var tx api.TransformerIn[externalCreateUser, createUser]

type TransformerInFunc

type TransformerInFunc[I, O any] func(*gin.Context, I) (O, error)

TransformerInFunc adapts a function into a TransformerIn.

func (TransformerInFunc[I, O]) TransformIn

func (f TransformerInFunc[I, O]) TransformIn(c *gin.Context, in I) (
	O,
	error,
)

TransformIn runs f.

Example (Transformer)
func() {
	defer func() { _ = recover() }()
	var subject TransformerInFunc[any, any]
	_, _ = subject.TransformIn(nil, nil)
}()
coretest.Println("done")
Output:
done

type TransformerOut

type TransformerOut[I, O any] interface {
	TransformOut(*gin.Context, I) (O, error)
}

TransformerOut remaps a handler-facing response DTO into an external response DTO inside the standard OK() envelope.

Example:

var tx api.TransformerOut[user, externalUser]

type TransformerOutFunc

type TransformerOutFunc[I, O any] func(*gin.Context, I) (O, error)

TransformerOutFunc adapts a function into a TransformerOut.

func (TransformerOutFunc[I, O]) TransformOut

func (f TransformerOutFunc[I, O]) TransformOut(c *gin.Context, in I) (
	O,
	error,
)

TransformOut runs f.

Example (Transformer)
func() {
	defer func() { _ = recover() }()
	var subject TransformerOutFunc[any, any]
	_, _ = subject.TransformOut(nil, nil)
}()
coretest.Println("done")
Output:
done

type TransportConfig

type TransportConfig struct {
	SwaggerEnabled         bool
	SwaggerPath            string
	GraphQLPath            string
	GraphQLEnabled         bool
	GraphQLPlayground      bool
	GraphQLPlaygroundPath  string
	WSEnabled              bool
	WSPath                 string
	SSEEnabled             bool
	SSEPath                string
	PprofEnabled           bool
	ExpvarEnabled          bool
	ChatCompletionsEnabled bool
	ChatCompletionsPath    string
	OpenAPISpecEnabled     bool
	OpenAPISpecPath        string
}

TransportConfig captures the configured transport endpoints and flags for an Engine.

It is intentionally small and serialisable so callers can inspect the active HTTP surface without rebuilding an OpenAPI document.

Example:

cfg := api.TransportConfig{SwaggerPath: "/swagger", WSPath: "/ws"}

type WebSocketClient

type WebSocketClient struct {
	URL    string
	Header http.Header
	Dialer *websocket.Dialer
}

WebSocketClient wraps a websocket.Dialer with predictable defaults for connecting to the framework's WebSocket endpoints.

Example:

client := api.NewWebSocketClient("wss://api.example.com/ws")
conn, resp, err := client.DialContext(ctx)

func NewWebSocketClient

func NewWebSocketClient(rawURL string, opts ...WebSocketClientOption) *WebSocketClient

NewWebSocketClient constructs a WebSocketClient with sensible defaults.

Example:

client := api.NewWebSocketClient("wss://api.example.com/ws")
Example (TransportClient)
func() {
	defer func() { _ = recover() }()
	_ = NewWebSocketClient("")
}()
coretest.Println("done")
Output:
done

func (*WebSocketClient) DialContext

func (c *WebSocketClient) DialContext(ctx context.Context) (
	*websocket.Conn,
	*http.Response,
	error,
)

DialContext opens the WebSocket connection and returns the negotiated connection plus the HTTP upgrade response.

The client accepts ws:// and wss:// URLs. The target is validated against the outbound SSRF guard before the handshake is attempted.

Example:

conn, resp, err := client.DialContext(ctx)
Example (TransportClient)
func() {
	defer func() { _ = recover() }()
	var subject *WebSocketClient
	_, _, _ = subject.DialContext(nil)
}()
coretest.Println("done")
Output:
done

type WebSocketClientOption

type WebSocketClientOption func(*WebSocketClient)

WebSocketClientOption configures a WebSocketClient.

func WithWebSocketDialer

func WithWebSocketDialer(dialer *websocket.Dialer) WebSocketClientOption

WithWebSocketDialer sets the dialer used to establish the connection.

Example:

client := api.NewWebSocketClient(url, api.WithWebSocketDialer(dialer))
Example (TransportClient)
func() {
	defer func() { _ = recover() }()
	_ = WithWebSocketDialer(nil)
}()
coretest.Println("done")
Output:
done

func WithWebSocketHeaders

func WithWebSocketHeaders(header http.Header) WebSocketClientOption

WithWebSocketHeaders adds request headers to the outbound WebSocket dial.

Example:

client := api.NewWebSocketClient(
    "wss://api.example.com/ws",
    api.WithWebSocketHeaders(http.Header{"Authorization": {"Bearer secret"}}),
)
Example (TransportClient)
func() {
	defer func() { _ = recover() }()
	_ = WithWebSocketHeaders(nil)
}()
coretest.Println("done")
Output:
done

type WebhookSigner

type WebhookSigner struct {
	// contains filtered or unexported fields
}

WebhookSigner produces and verifies HMAC-SHA256 signatures over webhook payloads. Spec §6: signed payloads (HMAC-SHA256) include a timestamp and a signature header so receivers can validate authenticity, integrity, and reject replays.

The signature format mirrors the PHP-side WebhookSignature service:

signature = HMAC-SHA256(timestamp + "." + payload, secret)

signer := api.NewWebhookSigner("supersecret")
headers := signer.Headers([]byte(`{"event":"workspace.created"}`))
// headers["X-Webhook-Signature"] is the hex digest
// headers["X-Webhook-Timestamp"] is the Unix timestamp string

func NewWebhookSigner

func NewWebhookSigner(secret string) *WebhookSigner

NewWebhookSigner constructs a signer that uses the given shared secret with the default timestamp tolerance (five minutes).

signer := api.NewWebhookSigner("shared-secret")
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	_ = NewWebhookSigner("")
}()
coretest.Println("done")
Output:
done

func NewWebhookSignerWithTolerance

func NewWebhookSignerWithTolerance(secret string, tolerance time.Duration) *WebhookSigner

NewWebhookSignerWithTolerance constructs a signer with a custom timestamp tolerance. A tolerance of zero or negative falls back to DefaultWebhookTolerance to avoid silently disabling replay protection.

signer := api.NewWebhookSignerWithTolerance("secret", 30*time.Second)
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	_ = NewWebhookSignerWithTolerance("", 0)
}()
coretest.Println("done")
Output:
done

func (*WebhookSigner) Headers

func (s *WebhookSigner) Headers(payload []byte) map[string]string

Headers returns the HTTP headers a sender should attach to a webhook request: X-Webhook-Signature and X-Webhook-Timestamp. The current Unix timestamp is used.

for k, v := range signer.Headers(payload) {
    req.Header.Set(k, v)
}
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	var subject *WebhookSigner
	_ = subject.Headers(nil)
}()
coretest.Println("done")
Output:
done

func (*WebhookSigner) IsTimestampValid

func (s *WebhookSigner) IsTimestampValid(timestamp int64) bool

IsTimestampValid reports whether the given Unix timestamp is within the signer's configured tolerance window relative to the current time.

if !signer.IsTimestampValid(ts) {
    return core.NewError("webhook timestamp expired")
}
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	var subject *WebhookSigner
	_ = subject.IsTimestampValid(0)
}()
coretest.Println("done")
Output:
done

func (*WebhookSigner) Sign

func (s *WebhookSigner) Sign(payload []byte, timestamp int64) string

Sign returns the hex-encoded HMAC-SHA256 of "timestamp.payload" using the signer's secret. Callers may pass any non-nil payload bytes (typically a JSON-encoded event body).

digest := signer.Sign(payload, time.Now().Unix())
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	var subject *WebhookSigner
	_ = subject.Sign(nil, 0)
}()
coretest.Println("done")
Output:
done

func (*WebhookSigner) SignNow

func (s *WebhookSigner) SignNow(payload []byte) (string, int64)

SignNow signs the payload using the current Unix timestamp and returns both the signature and the timestamp used.

sig, ts := signer.SignNow(payload)
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	var subject *WebhookSigner
	_, _ = subject.SignNow(nil)
}()
coretest.Println("done")
Output:
done

func (*WebhookSigner) Tolerance

func (s *WebhookSigner) Tolerance() time.Duration

Tolerance returns the configured maximum age tolerance for verification.

d := signer.Tolerance()
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	var subject *WebhookSigner
	_ = subject.Tolerance()
}()
coretest.Println("done")
Output:
done

func (*WebhookSigner) Verify

func (s *WebhookSigner) Verify(payload []byte, signature string, timestamp int64) bool

Verify reports whether the given signature matches the payload and the timestamp is within the signer's tolerance window. Comparison uses hmac.Equal to avoid timing attacks.

if signer.Verify(payload, sig, ts) {
    // accept event
}
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	var subject *WebhookSigner
	_ = subject.Verify(nil, "", 0)
}()
coretest.Println("done")
Output:
done

func (*WebhookSigner) VerifyRequest

func (s *WebhookSigner) VerifyRequest(r *http.Request, payload []byte) bool

VerifyRequest extracts the signature and timestamp headers from a request and verifies the given payload against them. Returns false when the headers are missing, malformed, or the signature does not match.

if !signer.VerifyRequest(r, payload) {
    http.Error(w, "invalid signature", http.StatusUnauthorized)
    return
}
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	var subject *WebhookSigner
	_ = subject.VerifyRequest(nil, nil)
}()
coretest.Println("done")
Output:
done

func (*WebhookSigner) VerifySignatureOnly

func (s *WebhookSigner) VerifySignatureOnly(payload []byte, signature string, timestamp int64) bool

VerifySignatureOnly compares the signature without checking timestamp freshness. Use it when timestamp validation is performed elsewhere or in tests where a stable timestamp is required.

ok := signer.VerifySignatureOnly(payload, sig, fixedTimestamp)
Example (Webhook)
func() {
	defer func() { _ = recover() }()
	var subject *WebhookSigner
	_ = subject.VerifySignatureOnly(nil, "", 0)
}()
coretest.Println("done")
Output:
done

Directories

Path Synopsis
cmd
gateway command
pkg
provider
Package provider defines the Service Provider Framework interfaces.
Package provider defines the Service Provider Framework interfaces.
stream
Package stream defines declarative SSE and WebSocket endpoint groups that can be mounted onto an api.Engine.
Package stream defines declarative SSE and WebSocket endpoint groups that can be mounted onto an api.Engine.

Jump to

Keyboard shortcuts

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