apptheory

package module
v0.2.0-rc.1 Latest Latest
Warning

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

Go to latest
Published: Jan 20, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

README

AppTheory — Multi-language Serverless Application Framework (Go, TypeScript, Python)

AppTheory is a TableTheory-style multi-language monorepo for building serverless applications with a shared runtime contract and cross-language drift prevention.

Distribution: GitHub Releases only (no npm/PyPI publishing).

Charter (M0)

AppTheory exists to provide a portable runtime core (and contract tests) for AWS serverless applications that must be first-class in Go, TypeScript, and Python.

Target audiences and use cases:

  • Platform and application teams building HTTP APIs on AWS Lambda (Lambda Function URL, API Gateway v2).
  • Event-driven workloads (SQS, EventBridge, DynamoDB Streams) and WebSockets are required for Lift parity and are tracked as remaining contract work (see docs/development/planning/apptheory/apptheory-gap-analysis-lesser.md).
  • Internal tooling and shared libraries that need consistent request/response semantics across languages.

Non-goals (near-term):

  • Not a general-purpose web framework; contract-first serverless runtime only.
  • Not registry-published packages (no npm or PyPI); releases ship via GitHub assets.

Public Names (M0)

  • Go module path: github.com/theory-cloud/apptheory
  • npm package: @theory-cloud/apptheory
  • Python distribution name: apptheory
  • Python import name: apptheory

Supported Runtimes (M0)

  • Go toolchain: 1.25.6
  • Node.js: 24
  • Python: 3.14

Runtime tiers (P0/P1/P2)

  • P0: routing + request/response normalization + error envelope
  • P1: request-id, tenant extraction, auth hooks, CORS, size/time guardrails, middleware ordering
  • P2 (default): P1 + observability hooks + rate limiting / load shedding policy hooks

Go runtime (P2 default)

The Go runtime implements the fixture-backed contract across P0/P1/P2 tiers (default: P2).

Minimal local invocation:

env := testkit.New()
app := env.App()

app.Get("/ping", func(ctx *apptheory.Context) (*apptheory.Response, error) {
	return apptheory.Text(200, "pong"), nil
})

resp := env.Invoke(context.Background(), app, apptheory.Request{Method: "GET", Path: "/ping"})
_ = resp

To force the P0 core (minimal surface area), pass apptheory.WithTier(apptheory.TierP0) when creating the app.

Unit test without AWS (deterministic time + IDs + HTTP event builder):

func TestHello(t *testing.T) {
	env := testkit.NewWithTime(time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC))
	env.IDs.Queue("req-1")

	app := env.App()
	app.Get("/hello", func(ctx *apptheory.Context) (*apptheory.Response, error) {
		return apptheory.MustJSON(200, map[string]any{
			"now_unix": ctx.Now().Unix(),
			"id":       ctx.NewID(),
		}), nil
	})

	event := testkit.APIGatewayV2Request("GET", "/hello", testkit.HTTPEventOptions{
		Headers: map[string]string{"x-request-id": "request-1"},
	})
	resp := env.InvokeAPIGatewayV2(context.Background(), app, event)

	if resp.StatusCode != 200 {
		t.Fatalf("expected status 200, got %d", resp.StatusCode)
	}
	if resp.Headers["x-request-id"] != "request-1" {
		t.Fatalf("expected x-request-id request-1, got %#v", resp.Headers["x-request-id"])
	}

	var body map[string]any
	if err := json.Unmarshal([]byte(resp.Body), &body); err != nil {
		t.Fatalf("parse response json: %v", err)
	}
	if body["id"] != "req-1" {
		t.Fatalf("expected id req-1, got %#v", body["id"])
	}
}

Start here:

  • Planning index: docs/development/planning/apptheory/README.md
  • Main roadmap: docs/development/planning/apptheory/apptheory-multilang-roadmap.md

Migration:

  • Lift → AppTheory (draft): docs/migration/from-lift.md

License:

  • Apache 2.0 (see LICENSE)

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

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

App is the root container for an AppTheory application.

AppTheory's runtime behavior is defined by a fixture-backed, versioned contract: `docs/development/planning/apptheory/supporting/apptheory-runtime-contract-v0.md`.

func New

func New(opts ...Option) *App

New creates a new AppTheory application container.

func (*App) Delete

func (a *App) Delete(pattern string, handler Handler, opts ...RouteOption) *App

func (*App) DynamoDB

func (a *App) DynamoDB(tableName string, handler DynamoDBStreamHandler) *App

DynamoDB registers a DynamoDB Streams handler by table name.

func (*App) EventBridge

func (a *App) EventBridge(selector EventBridgeSelector, handler EventBridgeHandler) *App

EventBridge registers an EventBridge handler.

Matching rules: - If selector.RuleName is set, it matches when any event resource ARN refers to that rule name. - Otherwise, it matches on selector.Source + selector.DetailType (when provided).

func (*App) Get

func (a *App) Get(pattern string, handler Handler, opts ...RouteOption) *App

func (*App) Handle

func (a *App) Handle(method, pattern string, handler Handler, opts ...RouteOption) *App

func (*App) HandleLambda

func (a *App) HandleLambda(ctx context.Context, event json.RawMessage) (any, error)

HandleLambda routes an untyped Lambda event to the correct AppTheory entrypoint.

Supported triggers: - API Gateway v2 (HTTP API) - API Gateway REST API v1 (Proxy) - Lambda Function URL - SQS - EventBridge - DynamoDB Streams - API Gateway v2 (WebSocket API)

func (*App) Post

func (a *App) Post(pattern string, handler Handler, opts ...RouteOption) *App

func (*App) Put

func (a *App) Put(pattern string, handler Handler, opts ...RouteOption) *App

func (*App) SQS

func (a *App) SQS(queueName string, handler SQSHandler) *App

SQS registers a handler for an SQS queue by queue name.

func (*App) Serve

func (a *App) Serve(ctx context.Context, req Request) (resp Response)

func (*App) ServeAPIGatewayProxy

func (a *App) ServeAPIGatewayProxy(ctx context.Context, event events.APIGatewayProxyRequest) events.APIGatewayProxyResponse

func (*App) ServeDynamoDBStream

func (a *App) ServeDynamoDBStream(ctx context.Context, event events.DynamoDBEvent) events.DynamoDBEventResponse

ServeDynamoDBStream routes a DynamoDB Streams event to the registered table handler and returns a partial batch failure response.

If the table is unrecognized, it fails closed by returning all records as failures.

func (*App) ServeEventBridge

func (a *App) ServeEventBridge(ctx context.Context, event events.EventBridgeEvent) (any, error)

ServeEventBridge routes an EventBridge event to the first matching handler.

If no handler matches, it returns (nil, nil).

func (*App) ServeSQS

func (a *App) ServeSQS(ctx context.Context, event events.SQSEvent) events.SQSEventResponse

ServeSQS routes an SQS event to the registered queue handler and returns a partial batch failure response.

If the queue is unrecognized, it fails closed by returning all messages as failures.

func (*App) WebSocket

func (a *App) WebSocket(routeKey string, handler WebSocketHandler) *App

type AppError

type AppError struct {
	Code    string
	Message string
}

AppError is a portable, client-safe error with a stable error code.

func (*AppError) Error

func (e *AppError) Error() string

type AuthHook

type AuthHook func(*Context) (identity string, err error)

type Clock

type Clock interface {
	Now() time.Time
}

Clock provides deterministic time for handlers and middleware.

type Context

type Context struct {
	Request Request
	Params  map[string]string

	RequestID       string
	TenantID        string
	AuthIdentity    string
	RemainingMS     int
	MiddlewareTrace []string
	// contains filtered or unexported fields
}

Context is the per-request context passed to handlers.

func (*Context) AsWebSocket

func (c *Context) AsWebSocket() *WebSocketContext

func (*Context) Context

func (c *Context) Context() context.Context

func (*Context) JSONValue

func (c *Context) JSONValue() (any, error)

func (*Context) NewID

func (c *Context) NewID() string

func (*Context) Now

func (c *Context) Now() time.Time

func (*Context) Param

func (c *Context) Param(name string) string

type DynamoDBStreamHandler

type DynamoDBStreamHandler func(*EventContext, events.DynamoDBEventRecord) error

type EventBridgeHandler

type EventBridgeHandler func(*EventContext, events.EventBridgeEvent) (any, error)

type EventBridgeSelector

type EventBridgeSelector struct {
	RuleName   string
	Source     string
	DetailType string
}

func EventBridgePattern

func EventBridgePattern(source, detailType string) EventBridgeSelector

func EventBridgeRule

func EventBridgeRule(ruleName string) EventBridgeSelector

type EventContext

type EventContext struct {
	RequestID   string
	RemainingMS int
	// contains filtered or unexported fields
}

EventContext is the shared context for non-HTTP Lambda triggers (SQS, EventBridge, DynamoDB Streams).

func (*EventContext) Context

func (c *EventContext) Context() context.Context

func (*EventContext) NewID

func (c *EventContext) NewID() string

func (*EventContext) Now

func (c *EventContext) Now() time.Time

type Handler

type Handler func(*Context) (*Response, error)

Handler is the request handler signature for AppTheory apps.

type IDGenerator

type IDGenerator interface {
	NewID() string
}

IDGenerator provides randomness for IDs/correlation IDs.

type Limits

type Limits struct {
	MaxRequestBytes  int
	MaxResponseBytes int
}

type LogRecord

type LogRecord struct {
	Level     string
	Event     string
	RequestID string
	TenantID  string
	Method    string
	Path      string
	Status    int
	ErrorCode string
}

type MetricRecord

type MetricRecord struct {
	Name  string
	Value int
	Tags  map[string]string
}

type ObservabilityHooks

type ObservabilityHooks struct {
	Log    func(LogRecord)
	Metric func(MetricRecord)
	Span   func(SpanRecord)
}

type Option

type Option func(*App)

func WithAuthHook

func WithAuthHook(hook AuthHook) Option

func WithClock

func WithClock(clock Clock) Option

func WithIDGenerator

func WithIDGenerator(ids IDGenerator) Option

func WithLimits

func WithLimits(limits Limits) Option

func WithObservability

func WithObservability(hooks ObservabilityHooks) Option

func WithPolicyHook

func WithPolicyHook(hook PolicyHook) Option

func WithTier

func WithTier(tier Tier) Option

func WithWebSocketClientFactory

func WithWebSocketClientFactory(factory WebSocketClientFactory) Option

func WithWebSocketSupport

func WithWebSocketSupport() Option

type PolicyDecision

type PolicyDecision struct {
	Code    string
	Message string
	Headers map[string][]string
}

type PolicyHook

type PolicyHook func(*Context) (*PolicyDecision, error)

type RandomIDGenerator

type RandomIDGenerator struct{}

RandomIDGenerator generates IDs using cryptographic randomness.

func (RandomIDGenerator) NewID

func (RandomIDGenerator) NewID() string

type RealClock

type RealClock struct{}

RealClock uses time.Now.

func (RealClock) Now

func (RealClock) Now() time.Time

type Request

type Request struct {
	Method   string
	Path     string
	Query    map[string][]string
	Headers  map[string][]string
	Cookies  map[string]string
	Body     []byte
	IsBase64 bool
}

Request is the canonical HTTP request model used by the AppTheory runtime.

type Response

type Response struct {
	Status   int
	Headers  map[string][]string
	Cookies  []string
	Body     []byte
	IsBase64 bool
}

Response is the canonical HTTP response model returned by AppTheory handlers.

func Binary

func Binary(status int, body []byte, contentType string) *Response

Binary builds a base64-encoded response for binary body content.

func JSON

func JSON(status int, value any) (*Response, error)

JSON builds an application/json response (utf-8).

func MustJSON

func MustJSON(status int, value any) *Response

MustJSON builds an application/json response (utf-8) and panics on marshal failure.

func MustSSEResponse

func MustSSEResponse(status int, events ...SSEEvent) *Response

MustSSEResponse builds an SSE response and panics on framing/serialization errors.

func SSEResponse

func SSEResponse(status int, events ...SSEEvent) (*Response, error)

SSEResponse builds a canonical AppTheory Response with properly framed SSE output.

func Text

func Text(status int, body string) *Response

Text builds a text/plain response (utf-8).

type RouteOption

type RouteOption func(*routeOptions)

func RequireAuth

func RequireAuth() RouteOption

type SQSHandler

type SQSHandler func(*EventContext, events.SQSMessage) error

type SSEEvent

type SSEEvent struct {
	ID    string
	Event string
	Data  any
}

SSEEvent is a Server-Sent Events (SSE) message.

Framing rules: - Optional: "id: <id>\n" - Optional: "event: <event>\n" - Data: one "data: <line>\n" per line (at least one line) - Terminator: "\n"

type SpanRecord

type SpanRecord struct {
	Name       string
	Attributes map[string]string
}

type Tier

type Tier string
const (
	TierP0 Tier = "p0"
	TierP1 Tier = "p1"
	TierP2 Tier = "p2"
)

type WebSocketClientFactory

type WebSocketClientFactory func(context.Context, string) (streamer.Client, error)

type WebSocketContext

type WebSocketContext struct {
	RequestID   string
	RemainingMS int

	ConnectionID       string
	RouteKey           string
	DomainName         string
	Stage              string
	EventType          string
	ManagementEndpoint string

	Body []byte
	// contains filtered or unexported fields
}

func (*WebSocketContext) Context

func (c *WebSocketContext) Context() context.Context

func (*WebSocketContext) NewID

func (c *WebSocketContext) NewID() string

func (*WebSocketContext) Now

func (c *WebSocketContext) Now() time.Time

func (*WebSocketContext) SendJSONMessage

func (c *WebSocketContext) SendJSONMessage(value any) error

func (*WebSocketContext) SendMessage

func (c *WebSocketContext) SendMessage(data []byte) error

type WebSocketHandler

type WebSocketHandler func(*Context) (*Response, error)

Directories

Path Synopsis
cmd
lift-migrate command
contract-tests
runners/go command
examples
pkg
limited
Package limited provides DynamoDB-backed rate limiting for AppTheory.
Package limited provides DynamoDB-backed rate limiting for AppTheory.
limited/middleware
Package middleware provides HTTP middleware for the AppTheory limited rate limiter.
Package middleware provides HTTP middleware for the AppTheory limited rate limiter.

Jump to

Keyboard shortcuts

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