api

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 21 Imported by: 0

README

api

The REST API server: HTTP handlers for store, RAG, graph, and reasoning, plus authentication middleware. openapi.json documents the contract.

Server

srv, err := api.NewServer(api.Config{
    Store:    store,
    Pipeline: ragPipeline,
    Graph:    graphStore,
    Reasoner: reasoner,
    // Host, Port, timeouts, Auth, ExemptPaths...
})
srv.ListenAndServe()      // or mount srv.Handler() in your own mux
srv.Shutdown(ctx)         // graceful

Endpoints (summary — see openapi.json): /healthz, /diagnostics, POST /upload, GET/POST /search (vector + hybrid), POST /rag, graph entity/relation routes, POST /reason, chunk delete routes.

Authentication

  • Authenticator interface + RequireAuth middleware.
  • APIKeyAuth (NewAPIKeyAuth(keys...), NewAPIKey()) — static API keys, checked as Authorization: Bearer or X-API-Key.
  • ScopedAPIKeyAuth / KeySpec — per-key namespace scoping (NamespaceScoper, RequestNamespaces).
  • JWTAuth (NewJWTAuth(cfg)) — JWT bearer auth.
  • Composite — OR-combine multiple authenticators.

Errors use a stable JSON envelope (Error, ErrCode* codes).

Documentation

Overview

Package api exposes Recall as an HTTP service using only the standard library. It provides a REST API over any store.Store, with optional RAG pipeline, knowledge graph, and reasoning support, plus API-key and JWT authentication.

The server is built as an http.Handler (Server.Handler), so it can be embedded in any routing setup or served standalone via Server.ListenAndServe. The OpenAPI 3.0 specification is served at GET /openapi.json.

Index

Constants

View Source
const (
	ErrCodeBadRequest   = "bad_request"
	ErrCodeNotFound     = "not_found"
	ErrCodeUnauthorized = "unauthorized"
	ErrCodeForbidden    = "forbidden"
	ErrCodeMethod       = "method_not_allowed"
	ErrCodeInternal     = "internal_error"
)

Error codes returned by the API.

Variables

This section is empty.

Functions

func NewAPIKey

func NewAPIKey() (string, error)

NewAPIKey generates a cryptographically random API key (48 base62-ish URL-safe characters) suitable for seeding Config.Authenticator.

func RequestNamespaces

func RequestNamespaces(r *http.Request) []string

RequestNamespaces returns the namespace scope imposed on the request by its authenticator (see NamespaceScoper), or nil when the request is unrestricted. Handlers use it to enforce namespace-scoped credentials.

func RequireAuth

func RequireAuth(a Authenticator, hints ...string) func(http.Handler) http.Handler

RequireAuth wraps an http.Handler with authentication. Requests that fail authentication receive a 401 with a JSON error envelope (a WWW-Authenticate hint is included when hints are given). Successful requests carry the subject in the request context (see Subject).

func Subject

func Subject(r *http.Request) string

Subject returns the authenticated subject set by the RequireAuth middleware, or "" when the request was not authenticated.

Types

type APIKeyAuth

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

APIKeyAuth authenticates requests by API key. The key is read from the X-API-Key header first, then from an "Authorization: Bearer <key>" header. The subject returned is the key itself, so callers can map keys to identities outside the API.

func NewAPIKeyAuth

func NewAPIKeyAuth(keys ...string) *APIKeyAuth

NewAPIKeyAuth creates an API-key authenticator from the given keys.

func (*APIKeyAuth) Authenticate

func (a *APIKeyAuth) Authenticate(r *http.Request) (string, bool)

Authenticate implements Authenticator.

type Authenticator

type Authenticator interface {
	// Authenticate returns the subject and true when the request carries
	// valid credentials, or "" and false otherwise.
	Authenticate(r *http.Request) (string, bool)
}

Authenticator validates an incoming request and returns the authenticated subject (e.g. the API key identity or JWT "sub" claim) when valid.

type Composite

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

Composite tries each authenticator in order and returns the first valid result.

func NewComposite

func NewComposite(auths ...Authenticator) *Composite

NewComposite creates a composite authenticator from the given authenticators (nil entries are skipped).

func (*Composite) Authenticate

func (c *Composite) Authenticate(r *http.Request) (string, bool)

Authenticate implements Authenticator.

func (*Composite) Namespaces

func (c *Composite) Namespaces(subject string) []string

Namespaces implements NamespaceScoper: the first sub-authenticator in order that reports a non-empty scope for the subject determines it, mirroring Authenticate's first-match semantics.

type Config

type Config struct {
	// Store is the knowledge store backing the API (required).
	Store store.Store

	// Pipeline is the RAG pipeline for POST /rag. Optional: when nil the
	// /rag endpoint returns 400.
	Pipeline *pipeline.RAGPipeline

	// Graph is the knowledge graph store for /graph endpoints. Optional.
	Graph store.GraphStore

	// Reasoner is the multi-hop reasoning engine for POST /graph/reason.
	// Optional: when nil the endpoint returns 400.
	Reasoner *reasoning.Engine

	// Authenticator, when non-nil, protects all endpoints except the
	// health/readiness/openapi paths (see ExemptPaths).
	Authenticator Authenticator

	// ExemptPaths are path prefixes served without authentication, in
	// addition to the defaults (/healthz, /readyz, /diagnostics,
	// /openapi.json).
	ExemptPaths []string

	// MaxUploadBytes caps the request body size for POST /upload.
	// Defaults to 10 MiB.
	MaxUploadBytes int64

	// Host is the listen address host (used by ListenAndServe). Defaults
	// to "127.0.0.1".
	Host string

	// Port is the listen port (used by ListenAndServe). Defaults to 8080.
	Port int

	// ReadTimeout bounds reading the entire request. Defaults to 30s.
	ReadTimeout time.Duration

	// WriteTimeout bounds writing the response. Defaults to 60s.
	WriteTimeout time.Duration

	// IdleTimeout bounds keep-alive connections. Defaults to 120s.
	IdleTimeout time.Duration

	// AllowCORS enables permissive CORS headers on all responses.
	AllowCORS bool
}

Config configures a Server.

type Error

type Error struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

Error is the standard JSON error envelope returned by all endpoints.

func (Error) Error

func (e Error) Error() string

type JWTAuth

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

JWTAuth validates HS256-signed JSON Web Tokens from the "Authorization: Bearer <token>" header. It verifies the signature and checks the exp and nbf claims, and (when configured) the iss and aud claims. The "sub" claim is returned as the subject; tokens without a subject are rejected.

func NewJWTAuth

func NewJWTAuth(cfg JWTConfig) (*JWTAuth, error)

NewJWTAuth creates a JWT authenticator, validating the configuration.

func (*JWTAuth) Authenticate

func (a *JWTAuth) Authenticate(r *http.Request) (string, bool)

Authenticate implements Authenticator.

type JWTConfig

type JWTConfig struct {
	// Secret is the shared HMAC-SHA256 signing secret (required).
	Secret string

	// Issuer, when non-empty, is required to match the "iss" claim.
	Issuer string

	// Audience, when non-empty, must appear in the "aud" claim.
	Audience string
}

JWTConfig configures JWTAuth.

type KeySpec

type KeySpec struct {
	// Key is the API key value (required).
	Key string

	// Namespaces restricts the key to these namespaces. Empty means all.
	Namespaces []string
}

KeySpec pairs an API key with the namespaces it may access. An empty Namespaces list grants access to all namespaces (the key behaves like a plain APIKeyAuth key).

type NamespaceScoper

type NamespaceScoper interface {
	Authenticator
	// Namespaces returns the allowed namespaces for the authenticated
	// subject, or nil when the subject is unrestricted (or unknown).
	Namespaces(subject string) []string
}

NamespaceScoper is an optional interface for Authenticators that impose per-subject namespace restrictions (e.g. ScopedAPIKeyAuth). It returns the namespaces a subject may access; nil or empty means unrestricted. When the authenticator passed to RequireAuth implements it, the scope is injected into the request context (see RequestNamespaces).

type ScopedAPIKeyAuth

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

ScopedAPIKeyAuth authenticates API keys with optional per-key namespace scope. The key is read from the X-API-Key header first, then from an "Authorization: Bearer <key>" header; the subject is the key itself. A key whose KeySpec lists namespaces is restricted to them: uploads must target an allowed namespace, and search, RAG, and graph results are limited to chunks in allowed namespaces. It implements NamespaceScoper, so the RequireAuth middleware injects the scope into the request context.

func NewScopedAPIKeyAuth

func NewScopedAPIKeyAuth(specs ...KeySpec) *ScopedAPIKeyAuth

NewScopedAPIKeyAuth creates a scoped API-key authenticator from the given key specs. Empty keys are skipped; duplicate keys keep the first spec.

func (*ScopedAPIKeyAuth) Authenticate

func (a *ScopedAPIKeyAuth) Authenticate(r *http.Request) (string, bool)

Authenticate implements Authenticator.

func (*ScopedAPIKeyAuth) Namespaces

func (a *ScopedAPIKeyAuth) Namespaces(subject string) []string

Namespaces implements NamespaceScoper. It returns a copy of the subject's allowed namespaces, or nil when the subject is unknown or unrestricted.

type Server

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

Server is a Recall HTTP API server.

func NewServer

func NewServer(cfg Config) (*Server, error)

NewServer creates a new Server, validating the configuration and wiring the HTTP handler (see Handler).

func (*Server) Addr

func (s *Server) Addr() string

Addr returns the listen address ("host:port") used by ListenAndServe.

func (*Server) Handler

func (s *Server) Handler() http.Handler

Handler returns the http.Handler implementing the API. It can be mounted in any http.ServeMux or served directly.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

ListenAndServe starts the HTTP server on the configured address and blocks until the server is stopped via Shutdown or a fatal network error occurs. It returns http.ErrServerClosed after a clean Shutdown.

func (*Server) ListenAndServeTLS

func (s *Server) ListenAndServeTLS(certFile, keyFile string) error

ListenAndServeTLS starts the TLS HTTP server with the given key and certificate files (PEM).

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown gracefully stops the server, waiting for in-flight requests up to the given context deadline. It is a no-op when the server was never started.

Jump to

Keyboard shortcuts

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