Documentation
¶
Overview ¶
Package apiserver provides an HTTP server that auto-generates REST endpoints from AILANG module exports. It wraps the embed.Engine to expose AILANG functions as JSON-in/JSON-out HTTP endpoints.
Usage:
srv := apiserver.New(basePath, "8080")
srv.LoadModules([]string{"ecommerce/api/handlers.ail"})
srv.Start() // blocks
Index ¶
- Constants
- type Config
- type ExportInfo
- type FunctionCallRequest
- type FunctionCallResponse
- type HealthResponse
- type MCPServer
- type ModuleInfo
- type ModulesListResponse
- type RouteEntry
- type RouterErrorDetail
- type Server
- func (s *Server) Close() error
- func (s *Server) GetEngine() *embed.Engine
- func (s *Server) GetModules() map[string]*ModuleInfo
- func (s *Server) LoadModules(paths []string) error
- func (s *Server) LoadProject(ctx context.Context, basePath string) error
- func (s *Server) Start() error
- func (s *Server) StartMCP() error
Constants ¶
const ( // ErrCodeRouteNotFound is emitted when a request path does not match any // registered @route on a route-driven server (i.e. the server has at // least one @route registered). Carries did-you-mean suggestions. ErrCodeRouteNotFound = "ROUTE_NOT_FOUND" // ErrCodeModuleNotLoaded is emitted only on legacy (zero-@route) servers // when a /api/{module}/{func} dispatch targets a module that isn't // loaded. On route-driven servers, unmatched paths return // ErrCodeRouteNotFound instead. ErrCodeModuleNotLoaded = "MODULE_NOT_LOADED" // ErrCodeFunctionNotFound is emitted when the module is loaded but the // requested function does not exist OR is hidden via @noexpose. The // code is intentionally shared with hidden-export errors so @noexpose // remains indistinguishable from "genuinely missing" to external callers. ErrCodeFunctionNotFound = "FUNCTION_NOT_FOUND" // ErrCodeMethodNotAllowed is emitted when the request method doesn't // match the @route method (or isn't POST/GET for the catch-all handler). ErrCodeMethodNotAllowed = "METHOD_NOT_ALLOWED" )
Router error codes. These are stable identifiers AI agents and SDKs can match on to decide how to recover from a router-layer failure.
These codes cover errors produced by the serve-api router and dispatch machinery BEFORE user code runs. Runtime errors from user code, coercion failures, and Result.Err → HTTP status mapping are covered by sibling sprints (M-DX-SERVE-API-ERROR-STATUS, M-DX-SERVE-API-COERCION).
const DefaultMaxUploadSize = 50 << 20
DefaultMaxUploadSize is the default maximum upload size (50MB).
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
Port string
CORS bool
FrontendPath string // optional: React project path for Vite proxy
StaticPath string // optional: built frontend files
Watch bool // enable file watching for hot reload
EffCtx interface{} // optional: pre-configured effect context (*effects.EffContext)
MCP bool // enable MCP endpoint at /mcp/
MCPOnly bool // run as MCP stdio server only (no HTTP)
A2A bool // enable A2A endpoints (/.well-known/agent.json, /a2a/)
MaxUploadSize int64 // max upload size in bytes (0 = DefaultMaxUploadSize)
APIKeyHeader string // HTTP header for API key auth (empty = no auth)
APIKeyEnv string // env var containing expected API key
LogLevel int // minimum severity for Debug output (0=DEBUG, 1=INFO, 2=WARN, 3=ERROR, 4=NONE)
RoutesOnly bool // only expose @route-annotated functions as HTTP endpoints
}
Config holds configuration for the API server.
type ExportInfo ¶
type ExportInfo struct {
Name string `json:"name"`
Type string `json:"type"` // human-readable type signature
Pure bool `json:"pure"` // whether the function is pure
Arity int `json:"arity"` // number of parameters (-1 if not a function)
ParamNames []string `json:"param_names,omitempty"` // parameter names in order (for named JSON binding)
ParamTypes []string `json:"param_types,omitempty"` // parameter type strings in order (for zero-value padding)
RouteMethod string `json:"route_method,omitempty"` // custom HTTP method from @route annotation
RoutePath string `json:"route_path,omitempty"` // custom URL path from @route annotation
IsRaw bool `json:"is_raw,omitempty"` // @raw annotation: pass full HttpRequest record
IsNowrap bool `json:"is_nowrap,omitempty"` // @nowrap annotation: skip FunctionCallResponse envelope
IsNoExpose bool `json:"is_no_expose,omitempty"` // @noexpose annotation: hide from HTTP endpoints
MCPName string `json:"mcp_name,omitempty"` // @mcp_name annotation: explicit MCP tool name override
DocComment string `json:"doc_comment,omitempty"` // doc comment (-- lines) preceding the function
}
ExportInfo describes a single exported function from an AILANG module.
type FunctionCallRequest ¶
type FunctionCallRequest struct {
Args []interface{} `json:"args,omitempty"`
}
FunctionCallRequest is the JSON body for calling an AILANG function. Use "args" for positional arguments (array), or provide a flat JSON object which is passed as a single record argument.
type FunctionCallResponse ¶
type FunctionCallResponse struct {
Result interface{} `json:"result,omitempty"`
Error string `json:"error,omitempty"`
ErrorDetail *RouterErrorDetail `json:"error_detail,omitempty"`
Module string `json:"module"`
Func string `json:"func"`
ElapsedMs int64 `json:"elapsed_ms"`
}
FunctionCallResponse is the JSON response from a function call.
For error responses, the flat `Error` field is preserved for backward compatibility, and new clients should prefer the structured `ErrorDetail` envelope which carries a stable error code and optional did-you-mean hints. The flat `Error` string always mirrors `ErrorDetail.Message` when both are set.
type HealthResponse ¶
type HealthResponse struct {
Status string `json:"status"`
ModulesCount int `json:"modules_count"`
ExportsCount int `json:"exports_count"`
}
HealthResponse is the response for GET /api/_health.
type MCPServer ¶
type MCPServer struct {
// contains filtered or unexported fields
}
MCPServer wraps an apiserver.Server to expose its functions as MCP tools.
func NewMCPServer ¶
NewMCPServer creates an MCP server from an apiserver.Server. All loaded modules' exported functions are registered as MCP tools.
func (*MCPServer) HTTPHandler ¶
HTTPHandler returns an HTTP handler for the MCP server using streamable HTTP transport.
type ModuleInfo ¶
type ModuleInfo struct {
// Path is the RelPath projection (forward-slash relative path with
// .ail stripped). Kept as the primary JSON field for backwards compat.
Path string `json:"path"`
Exports []ExportInfo `json:"exports"`
// PhysicalPath is the symlink-resolved absolute file path. This is
// the module's *identity*: two ModuleInfo values with the same
// PhysicalPath refer to the same physical source file, regardless of
// how they were discovered. This is the key used in s.modules.
PhysicalPath string `json:"-"`
// CanonicalID is the pipeline's canonical module ID (used by loader
// cache and callFunction dispatch). Example: "docparse/services/mcp_tools".
CanonicalID string `json:"-"`
// DeclaredPath is the `module X` header as written in source. Used
// to resolve imports from other local modules. Usually matches
// CanonicalID; differs under `module_prefix` aliasing.
DeclaredPath string `json:"-"`
// File is the parsed AST for the source file. Used for doc comment
// extraction and by the extract* helpers during registration.
File *ast.File `json:"-"`
// Iface is the type-checked interface from the pipeline. Used by
// callFunction for signature lookup and by the MCP schema generator.
Iface *iface.Iface `json:"-"`
}
ModuleInfo holds metadata about a loaded AILANG module.
M-SERVEAPI-UNIFY: ModuleInfo is the single source of truth for a local module's identity and all its projections. It is keyed in s.modules by PhysicalPath (symlink-resolved absolute file path) — NOT by the derived `Path` field. Every projection consumer (HTTP routes, OpenAPI, MCP, A2A, function dispatch) reads the field it needs from here, so drift between projection key derivations is structurally impossible.
Non-JSON fields (PhysicalPath, File, Iface) are not serialized in the /modules endpoint response to keep the public API shape unchanged.
type ModulesListResponse ¶
type ModulesListResponse struct {
Modules []*ModuleInfo `json:"modules"`
Count int `json:"count"`
}
ModulesListResponse is the response for GET /api/_meta/modules.
type RouteEntry ¶
type RouteEntry struct {
Method string // "GET", "POST", etc.
Path string // "/general/v0/general"
Module string // module path
Function string // function name
IsRaw bool // @raw: pass full HttpRequest record instead of parsed args
IsNowrap bool // @nowrap: skip FunctionCallResponse envelope, return raw JSON
ParamNames []string // parameter names for named JSON binding
ParamTypes []string // parameter type strings for zero-value padding
}
RouteEntry represents a custom route defined by a @route annotation.
type RouterErrorDetail ¶
type RouterErrorDetail struct {
// Code is a stable identifier (e.g. "ROUTE_NOT_FOUND"). Clients match
// on this rather than the human-readable Message.
Code string `json:"code"`
// Message is a human-readable description of what went wrong. Always
// mirrors the flat FunctionCallResponse.Error field for backward compat.
Message string `json:"message"`
// Retryable indicates whether the same request could succeed if retried
// without modification. Router-layer errors are almost always false.
Retryable bool `json:"retryable"`
// SuggestedFix is an optional human-readable hint for how to recover.
// For ROUTE_NOT_FOUND, this is populated with "Did you mean ...?" when
// a close route match exists. May be empty.
SuggestedFix string `json:"suggested_fix,omitempty"`
// AvailableRoutes is an optional list of registered routes that might
// be relevant to the failed request (e.g. routes sharing a path prefix).
// Capped at 10 entries. Each entry is formatted as "METHOD /path".
AvailableRoutes []string `json:"available_routes,omitempty"`
}
RouterErrorDetail is the structured, AI-first error envelope emitted by the serve-api router layer. It's attached to FunctionCallResponse.ErrorDetail so clients can either match on the flat `error` string (backward compat) or on the structured `error_detail.code` field (preferred).
The envelope intentionally mirrors the shape that docparse and other serve-api consumers already use for their own typed errors, so AI agents can use a single error-handling path across all error sources.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the API server that exposes AILANG functions as REST endpoints.
func (*Server) GetEngine ¶
GetEngine returns the underlying embed.Engine for advanced wiring (e.g., connecting FnCaller for stream event handlers).
func (*Server) GetModules ¶
func (s *Server) GetModules() map[string]*ModuleInfo
GetModules returns a copy of the loaded module info map.
func (*Server) LoadModules ¶
LoadModules compiles and loads AILANG modules from the given paths. Each path can be a .ail file or a directory (scanned recursively for .ail files).
M-SERVEAPI-UNIFY: both directory and file paths route through the unified loader. Directories go through LoadProject (project-wide single pass); single files go through loadFile, which compiles the file and registers every module from result.Modules via the SAME registerModule write site. There is no longer a separate dep-discovery loop — drift between projection key derivations is structurally impossible.
func (*Server) LoadProject ¶
LoadProject is the M-SERVEAPI-UNIFY replacement for the per-file loadFile + dep-discovery loop. It walks basePath for .ail files and compiles each one through the pipeline, registering every module in result.Modules via the single-write-site registerModule.
Duplicate work is avoided by tracking compiled physical paths: once a file has been seen in some result.Modules pass, a direct pipeline run for that file is skipped (the loader cache may also short-circuit but this avoids even the cache lookup).
Unlike the old path, LoadProject has ONE registration site and no per-file dedup glue. Projection drift between main path and dep-discovery is structurally impossible because there is no dep-discovery.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package schema converts AILANG type signatures to JSON Schema objects.
|
Package schema converts AILANG type signatures to JSON Schema objects. |
|
Package templates provides embedded templates for scaffolding AILANG web apps.
|
Package templates provides embedded templates for scaffolding AILANG web apps. |