api

package
v0.0.0-...-d8a54d3 Latest Latest
Warning

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

Go to latest
Published: Feb 21, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Overview

Package api provides the JSON REST API server for Koopa.

Architecture

The API server uses Go 1.22+ routing with a layered middleware stack:

Recovery → RequestID → Logging → CORS → RateLimit → User → Session → CSRF → Routes

Health probes (/health, /ready) bypass the middleware stack via a top-level mux, ensuring they remain fast and unauthenticated.

Endpoints

Health probes (no middleware):

  • GET /health — returns {"status":"ok"}
  • GET /ready — returns {"status":"ok"}

CSRF provisioning:

  • GET /api/v1/csrf-token — returns pre-session or session-bound token

Session CRUD (ownership-enforced):

  • POST /api/v1/sessions — create new session
  • GET /api/v1/sessions — list caller's sessions
  • GET /api/v1/sessions/{id} — get session by ID
  • GET /api/v1/sessions/{id}/messages — get session messages
  • DELETE /api/v1/sessions/{id} — delete session
  • GET /api/v1/sessions/{id}/export — export session

Chat (ownership-enforced):

  • POST /api/v1/chat — initiate chat, returns stream URL
  • GET /api/v1/chat/stream — SSE endpoint for streaming responses

Search:

  • GET /api/v1/search — full-text search across messages

Stats:

  • GET /api/v1/stats — usage statistics (sessions, messages, memories)

Memory (ownership-enforced):

  • GET /api/v1/memories — list memories
  • POST /api/v1/memories — create memory
  • DELETE /api/v1/memories/{id} — delete memory
  • GET /api/v1/memories/search — search memories

CSRF Token Model

Two token types prevent cross-site request forgery:

  • Pre-session tokens ("pre:nonce:timestamp:signature"): issued before a session exists, valid for the first POST /sessions call.

  • Session-bound tokens ("timestamp:signature"): bound to a specific session via HMAC-SHA256, verified with constant-time comparison.

Both expire after 1 hour with 5 minutes of clock skew tolerance.

Session Ownership

All session-accessing endpoints verify that the requested resource matches the caller's session cookie. This prevents session enumeration and cross-session data access.

Error Handling

All responses use an envelope format:

Success: {"data": <payload>}
Error:   {"error": {"code": "...", "message": "..."}}

Tool errors during chat are sent as SSE events (event: error), not HTTP error responses, since SSE headers are already committed.

SSE Streaming

Chat responses stream via Server-Sent Events with typed events:

  • chunk: incremental text content
  • tool_start: tool execution began
  • tool_complete: tool execution succeeded
  • tool_error: tool execution failed
  • done: final response with session metadata
  • error: flow-level error

Security

The middleware stack enforces:

  • CSRF protection for state-changing requests
  • Per-IP rate limiting (token bucket, 60 req/min burst)
  • CORS with explicit origin allowlist
  • Security headers (CSP, HSTS, X-Frame-Options, etc.)
  • HttpOnly, Secure, SameSite=Lax session cookies

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func WriteError

func WriteError(w http.ResponseWriter, status int, code, message string, logger *slog.Logger)

WriteError writes a JSON error response wrapped in an envelope. If logger is nil, falls back to slog.Default().

SECURITY: The message parameter MUST be a static, user-friendly string. NEVER pass err.Error() or any dynamic error content — this prevents database schema details, file paths, and internal state from leaking to clients (CWE-209). Log the full error server-side instead.

SECURITY: The status parameter MUST be a static http.Status* constant. NEVER pass a dynamic status code from a variable or third-party library.

func WriteJSON

func WriteJSON(w http.ResponseWriter, status int, data any, logger *slog.Logger)

WriteJSON writes data wrapped in an envelope as JSON. For nil data, writes no body (use with 204 No Content). If logger is nil, falls back to slog.Default().

Types

type Error

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

Error is the JSON body for error responses.

type Server

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

Server is the JSON API HTTP server.

func NewServer

func NewServer(ctx context.Context, cfg ServerConfig) (*Server, error)

NewServer creates a new API server with all routes configured. ctx controls the lifetime of background goroutines (pending query cleanup).

func (*Server) Handler

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

Handler returns the server as an http.Handler.

type ServerConfig

type ServerConfig struct {
	Logger       *slog.Logger
	ChatAgent    *chat.Agent    // Optional: nil disables AI title generation
	ChatFlow     *chat.Flow     // Optional: nil enables simulation mode
	SessionStore *session.Store // Required
	MemoryStore  *memory.Store  // Optional: nil disables memory management API
	Pool         *pgxpool.Pool  // Optional: nil disables pool stats in /ready
	CSRFSecret   []byte         // Required: 32+ bytes
	CORSOrigins  []string       // Allowed origins for CORS
	IsDev        bool           // Enables HTTP cookies (no Secure flag)
	TrustProxy   bool           // Trust X-Real-IP/X-Forwarded-For headers (behind reverse proxy)
	RateBurst    int            // Rate limiter burst size per IP (0 = default 60)
}

ServerConfig contains configuration for creating the API server.

Jump to

Keyboard shortcuts

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