mountkit

package
v0.1.45 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package mountkit mounts a forge Connect service onto an http.ServeMux.

Why a library

Earlier forge versions emitted a per-service Mount closure in the generated inventory: each closure called svc.Register(mux, opts...), then conditionally svc.RegisterHTTP(...) and svc.RegisterWebhookRoutes(...) — the same handful of lines repeated once per service, gated by a codegen flag (HasWebhooks). That body is uniform across every service and every project, so it belongs in one tested library function rather than in N generated closures.

mountkit.RegisterService replaces that closure. It is interface-driven: it asks the service value which capabilities it has (required Connect registration, optional plain-HTTP routes, optional webhook routes) by type-asserting small capability interfaces, and invokes whatever is present. No per-service codegen, no hard dependency on any consumer's concrete service type.

What it does NOT do

mountkit adds no interceptors of its own: RegisterService threads the caller's opts straight through to Register.

mountkit does not build the HTTP middleware stack the optional registrars consume — that stack (recovery / logging / audit, e.g. forge/pkg/middleware.HTTPStack) is wired from the project's middleware package, so the caller constructs it and passes it via WithHTTPStack. When no stack is supplied, optional HTTP/webhook routes are mounted with an identity (pass-through) stack.

The boundary with serverkit

serverkit takes an already-composed http.Handler and owns the runtime lifecycle; it knows nothing about service names or mounting. mountkit sits one level ABOVE serverkit, in the mux-composition step the generated cmd-server shim performs before handing the finished handler to serverkit.Run. They are deliberately separate packages so neither has to import the other's concerns.

Usage in generated code

The generated cmd-server shim (or the data-only inventory's Mount closure, during migration) calls RegisterService once per selected service:

stack := fmw.HTTPStack(logger, middleware.ClaimsFromContext)
for _, svc := range selectedServices {
    mountkit.RegisterService(mux, svc, opts, mountkit.WithHTTPStack(stack))
}

opts is the shared []connect.HandlerOption (observe interceptors, read/send limits) already composed once for the whole process.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RegisterService

func RegisterService(mux *http.ServeMux, svc any, opts []connect.HandlerOption, mountOpts ...Option)

RegisterService mounts a single forge Connect service onto mux.

svc MUST implement Registrar; RegisterService asserts it and panics with a clear message if absent — handing a value without Register to the mount loop is a programming error caught at boot, not a recoverable runtime condition. It then calls Register(mux, opts...), threading the caller's shared opts through UNCHANGED (mountkit adds no interceptors of its own — see the package doc).

After the required Connect registration, RegisterService type-asserts each OPTIONAL capability (HTTPRegistrar, WebhookRegistrar) and invokes any the value implements, passing the stack from WithHTTPStack (or an identity stack when none was supplied). A service implementing only Registrar mounts exactly its Connect handler and nothing else.

Types

type HTTPRegistrar

type HTTPRegistrar interface {
	RegisterHTTP(mux *http.ServeMux, stack func(http.Handler) http.Handler)
}

HTTPRegistrar is an OPTIONAL capability for services that expose plain (non-Connect) HTTP routes — OAuth callbacks, hand-rolled REST, webhook receivers wired by hand. The signature mirrors the generated service.go's RegisterHTTP method exactly:

RegisterHTTP(mux *http.ServeMux, stack func(http.Handler) http.Handler)

stack is the project's HTTP middleware (recovery / logging / audit, e.g. forge/pkg/middleware.HTTPStack) that the route should be wrapped in. mountkit does not build the stack — the caller supplies it via WithHTTPStack; when omitted, an identity (pass-through) stack is used so the route still mounts.

Auth is intentionally NOT part of this stack: plain-HTTP routes commonly authenticate differently from Connect RPCs (webhook-signature vs JWT), so per-route auth stays the service's responsibility.

type Option

type Option func(*options)

Option configures a RegisterService call.

func WithHTTPStack

func WithHTTPStack(stack func(http.Handler) http.Handler) Option

WithHTTPStack supplies the HTTP middleware stack passed to the optional HTTPRegistrar / WebhookRegistrar capabilities. The same stack feeds both. A nil stack is treated as absent (identity pass-through).

When a service implements neither optional capability, the stack is never consulted, so callers that mount only pure-Connect services may omit it.

type Registrar

type Registrar interface {
	// Register mounts the service's Connect handler on mux, applying the
	// supplied handler options (the shared interceptor chain + payload
	// limits). RegisterService passes the caller's opts through unchanged.
	Register(mux *http.ServeMux, opts ...connect.HandlerOption)
}

Registrar is the REQUIRED capability every mountable forge service implements: it registers its Connect handler on the mux. The generated service.go's Register method (which calls the protoc-gen-connect-go New<Svc>Handler and mux.Handle's the result) satisfies it directly.

A service value that does not implement Registrar cannot be mounted — RegisterService panics, because that is a boot-time programming error (a non-service was handed to the mount loop), not a runtime condition to recover from.

type WebhookRegistrar

type WebhookRegistrar interface {
	RegisterWebhookRoutes(mux *http.ServeMux, stack func(http.Handler) http.Handler)
}

WebhookRegistrar is an OPTIONAL capability for services that own forge.yaml-declared webhook routes. forge generates the RegisterWebhookRoutes method (in webhook_routes_gen.go) for exactly those services; its signature is identical to RegisterHTTP:

RegisterWebhookRoutes(mux *http.ServeMux, stack func(http.Handler) http.Handler)

It is kept as a SEPARATE capability from HTTPRegistrar (rather than folded into it) because the two are generated independently — a service may declare webhooks without overriding RegisterHTTP, or vice versa — and RegisterService invokes whichever subset the value implements. The same caller-supplied stack feeds both.

Directories

Path Synopsis
Package inventory owns the DATA-ONLY service descriptor type and reader helpers behind the generated internal/app/inventory_gen.go's `var Inventory = []inventory.ComponentInfo{...}`.
Package inventory owns the DATA-ONLY service descriptor type and reader helpers behind the generated internal/app/inventory_gen.go's `var Inventory = []inventory.ComponentInfo{...}`.

Jump to

Keyboard shortcuts

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