1 API Architecture and Design Approach
The Axebow architecture specifies a REST API as the primary interface for interacting with a platform instance, accessible only to authenticated users. The API design combines traditional RESTful endpoints with a reactive WebSocket channel for real-time updates.
1.1 Dual Interface Strategy
The API offers two complementary interfaces:
- REST Interface
- Provides standard HTTP endpoints for all platform operations. Clients make HTTP requests (GET, POST, PUT, DELETE, PATCH) to resource URLs and receive JSON responses. This interface is stateless, requiring authentication on each request, and is ideal for scripting, automation, command-line tools, and traditional web service integrations.
- WebSocket Interface
- Establishes persistent, bidirectional connections that support both request-response operations and server-initiated push notifications. Clients can execute any API operation over WebSocket using a JSON message protocol, while simultaneously receiving real-time updates about entity state changes. This interface maintains connection state and is ideal for interactive applications, dashboards, and scenarios requiring immediate notification of system changes.
Both interfaces access identical endpoints and operations. A service deployment initiated via REST behaves identically to one initiated via WebSocket. The choice of interface is purely a matter of client requirements and connection model preference.
1.2 Synchronous and Asynchronous Operations
All API operations share a common synchronous authorization phase, but execution strategy varies based on operation complexity:
Synchronous Authentication (interface-dependent):
HTTP Interface: Authentication occurs on every request. Each HTTP request must include a bearer token in the Authorization header, which is validated before the handler executes.
WebSocket Interface: Authentication occurs once during connection establishment. The bearer token is validated during the HTTP upgrade handshake. Once the WebSocket connection is established, all subsequent messages on that connection are inherently authenticated.
Synchronous Authorization and Validation (all operations):
When an operation is invoked (via HTTP request or WebSocket message), the API handler immediately:
Authorizes the operation against the user’s permissions (scope-based authorization)
Validates the request parameters and payload (schema validation)
Execution Strategy (operation-dependent):
Lightweight Operations (fully synchronous):
Operations that complete quickly, such as tenant creation, account registration, resource creation, execute synchronously within the handler. The API performs the operation, commits changes to the database, and returns the final result immediately.
Examples:
POST /tenant/:tenant
POST /tenant/:tenant/account/:account
POST /tenant/:tenant/secret/:secret
Heavy Operations (asynchronous):
Operations requiring complex orchestration, such as service deployments, resource deletions with dependencies, tenant cleanup, initiate the workflow synchronously but delegate actual execution to background controllers. The API creates initial records, returns immediately, and allows controllers to process the operation asynchronously through multiple stages.
Examples:
POST /tenant/:tenant/service/:service
DELETE /tenant/:tenant
DELETE /tenant/:tenant/account/:account
During asynchronous execution:
Controllers process the operation through a series of specialized stages
Each stage updates entity status fields to reflect progress
Errors and completion trigger database updates
WebSocket-connected clients receive push notifications of all status changes
This hybrid approach ensures that simple operations provide immediate results while complex orchestrations don’t block API responses, maintaining fast and predictable response times across all endpoints.
2 API Organization and Structure
The API is organized into 15 API groups, each focusing on a specific domain of platform functionality. This modular structure allows for clear separation of concerns, consistent patterns across related operations, and straightforward discovery of available endpoints.
2.1 API Groups and Modules
The API comprises the following groups:
| Group | Description | Example Endpoints |
|---|---|---|
tenant |
Tenant lifecycle management | POST /api/{version}/tenant/:tenant, GET /api/{version}/tenant, DELETE /api/{version}/tenant/:tenant |
service |
Service deployment and management | POST /api/{version}/tenant/:tenant/service/:service, GET /api/{version}/tenant/:tenant/service, PUT /api/{version}/tenant/:tenant/service/:service/recover |
revision |
Service revision management | GET /api/{version}/tenant/:tenant/service/:service/revision, DELETE /api/{version}/tenant/:tenant/service/:service/revision/:revision |
account |
Cloud provider account configuration | POST /api/{version}/tenant/:tenant/account/:account, GET /api/{version}/tenant/:tenant/account |
environment |
Deployment environment management | POST /api/{version}/tenant/:tenant/environment/:environment, PATCH /api/{version}/tenant/:tenant/environment/:environment |
link |
Service interconnection | POST /api/{version}/tenant/:tenant/link/:link, GET /api/{version}/tenant/:tenant/link |
resources |
Resource management (secrets, domains, ports, certificates) | POST /api/{version}/tenant/:tenant/secret/:secret, GET /api/{version}/tenant/:tenant/domain |
user |
User identity and tenant membership | GET /api/{version}/user, POST /api/{version}/tenant/:tenant/user/:user, DELETE /api/{version}/tenant/:tenant/user/:user |
token |
API token generation and management | POST /api/{version}/token/:token, GET /api/{version}/token, DELETE /api/{version}/token/:token |
plans |
Plan provider integration | GET /api/{version}/planprovider/:provider/plan, POST /api/{version}/planprovider/:provider/plan/:plan/instance |
marketplace |
Module search, bundle upload, schema retrieval | GET /api/{version}/marketplace, POST /api/{version}/marketplace/bundle, GET /api/{version}/marketplace/bundle/:bundle/manifest |
reporting |
Usage data and vCPU consumption reports | GET /api/{version}/reporting/vcpu |
operations |
Group reserved for platform operator actions | DELETE /api/{version}/operations/playground-tenant, GET /api/{version}/operations/debug/get |
dregistry |
Docker registry configuration | POST /api/{version}/tenant/:tenant/dregistry/:dregistry, GET /api/{version}/tenant/:tenant/dregistry |
misc |
Platform information, health checks, WebSocket endpoint | GET /platform, GET /health, GET /api/{version}/ws |
Each group is implemented as a directory under /apps/ksds/src/apigroups/<group>/ containing:
handlers/http/apis.ts: Route and schema definitions, depends on its facade definitionshandlers/http/http.ts: Handler implementationshandlers/http/types.ts: Request/response TypeScript typeshandlers/ws/…: WebSocket-specific handlers, similar to http ones.
2.2 Endpoint Pattern Format
All API endpoints follow a hierarchical resource pattern:
<METHOD> /api/<version>/<entity_type>/[entity_name]/[<child_type>/[child_name]/.../[section]]?[params]
Components:
<METHOD>: HTTP verb (GET, POST, PUT, PATCH, DELETE)<version>: API version<entity_type>: Top-level entity (e.g.,tenant,user,token)[entity_name]: Specific entity identifier[<child_type>/<child_name>]: Nested child resources (e.g.,/tenant/T/service/S/revision/R)[section]: Special operation suffix (e.g.,/recover,/log,/manifest)[params]: Query string parameters for filtering, pagination, options
Examples:
GET/api/{version}/tenant— List all tenants user can accessPOST/api/{version}/tenant/acme— Create tenant named "acme"GET/api/{version}/tenant/acme/service— List services in tenant "acme"POST/api/{version}/tenant/acme/service/web— Deploy service "web" in tenant "acme"GET/api/{version}/tenant/acme/service/web/revision— List revisions of service "web"DELETE/api/{version}/tenant/acme/service/web— Delete service revision "web"
6 Response Formats and Error Handling
The API uses consistent response formats for both success and error cases, enabling clients to handle responses uniformly regardless of endpoint or operation type.
6.1 Success Response Format
Successful operations return an HTTP 200 with a JSON body:
Fields:
data: The result of the operation (entity record, list of entities, computed value)
6.2 Error Response Format
Error responses use appropriate HTTP status codes with a JSON body:
Fields:
code: Machine-readable error codecontent: Human-readable error message or structured error details
6.3 Error Code System
Axebow defines over many error codes categorized by type, some of them are:
Authentication/Authorization Errors (HTTP 401, 403):
unauthorized: Missing or invalid authentication tokenforbidden: User lacks required permissions_token_expired_: Authentication token has expired_invalid_scope_: Operation not permitted by token scopes
Resource Errors (HTTP 404, 409):
_tenant_not_found_,_service_not_found_,_environment_not_found_: Entity does not exist_tenant_exists_,_service_exists_,_user_exists_: Entity already exists (conflict)_resource_conflict_: Port or domain already in use by another service
Quota/Limit Errors (HTTP 409, 403):
_limits_exceeded_: Operation would exceed plan limits
Rate Limiting (HTTP 429):
_rate_limit_exceeded_: Request rate limit exceeded_payload_too_large_: Request payload exceeds size limit (1MB for WebSocket)
Operational Errors (HTTP 500):
generic: Unexpected internal error occurred
Feature Errors (HTTP 403):
disabled: API group is disabled via feature flag
6.4 Reference IDs for Defects
When unexpected errors occur:
Reference ID generated: Unique UUID created
Error logged: Full error stack trace logged with reference ID
Trace correlation: Reference ID added to trace span
User notification: Reference ID included in error response
Users can report the reference ID in support requests, allowing to correlate the error with logs and traces for root cause analysis.
7 WebSocket API
While the REST API provides straightforward request-response interactions, many client applications (notably Axebow’s dashboard) require real-time notifications of platform state changes. Polling REST endpoints for updates is inefficient and introduces latency. The WebSocket API solves this by establishing persistent, bidirectional connections that support both request-response operations and server-initiated push notifications.
The WebSocket API is not a separate interface, it shares the same business logic, facades, authorization model, and error handling as the REST API. Every REST operation can be performed over WebSocket, with the added benefit of receiving real-time updates about any entity changes relevant to the authenticated user.
7.1 Connection Establishment and Authentication
The WebSocket endpoint is located at:
/api/{version}/ws
Authentication:
The bearer token is validated during the HTTP upgrade phase:
Token extraction: Bearer token extracted from
AuthorizationheaderUser authentication: Token validated, user record loaded
If authentication fails, the WebSocket upgrade is rejected with HTTP 401 or 403.
Connection Initialization:
Upon successful upgrade, the server initializes the connection state:
Connection ID: Unique UUIDv7 identifier generated for this connection
Incoming Queue: Bounded queue (capacity: 100 messages) for client → server messages
Outgoing Queue: Unbounded queue for server → client messages
Pending Requests: HashMap tracking in-flight request-response correlations
Subscriptions: HashSet of topic subscriptions (dynamically managed based on user permissions)
Initial Context Synchronization:
Immediately after connection establishment, the server sends all entities the user can access:
User’s own user record
All tenant records (for tenants the user is a member of)
All environments, services, revisions, and resources within those tenants
All service links (where user is a member of either client or server tenant)
All provider user records
All plan instance records
This ensures clients have complete initial state before receiving incremental updates.
7.2 Message Protocol and Format
All WebSocket communication uses JSON messages with a standarized schema:
7.3 Message Types
The WebSocket protocol supports five message types:
7.3.1 Request Messages
Purpose: Execute API operations over WebSocket
Direction: Client → Server
Format:
Payload Structure:
Path parameters:
payload.tenant,payload.service, etc.Query parameters:
payload.filter,payload.limit, etc.Request body:
payload.spec(equivalent to HTTP POST/PUT body)
Topic Format: <api_group>:<endpoint_id>
Examples: tenant:create_tenant, service:list_services, user:get_user
7.3.2 Success Messages
Purpose: Return successful operation results
Direction: Server → Client
Format:
The payload follows the same structure as REST API success responses ({data, events}).
7.3.3 Error Messages
Purpose: Return operation errors
Direction: Server → Client
Format:
Error payloads include:
status: HTTP status code equivalent (400, 401, 403, 404, 409, 429,code: Machine-readable error code (same codes as REST API)content: Human-readable error details
7.3.4 Event Messages
Purpose: Push real-time entity change notifications
Direction: Server → Client
Format:
Delete Events:
Events are pushed automatically when any entity changes that the user has permissions to observe.
7.3.5 Multipart Request Messages
Purpose: Upload large files (bundles) that exceed the 1MB message size limit
Direction: Client → Server (three-phase protocol)
See "Multipart Upload Protocol" section below for complete details.
7.5 Multipart Upload Protocol
Large file uploads (e.g., service bundles) cannot be sent in a single WebSocket message due to the 1MB message size limit. The multipart upload protocol solves this by chunking data across multiple messages.
Protocol Overview:
The multipart upload follows a three-phase protocol:
Phase 1: Initialization (
part:"start")Phase 2: Data Transfer (
part:<number>)Phase 3: Finalization (
part:"end")
7.5.1 Phase 1: Initialization
Client sends a multipart request to initiate the upload:
Server Actions:
Validates user has permission for the tenant
Generates unique
uploadId(UUIDv7)Initializes
MultipartUploadStatein memoryReturns success response:
7.5.2 Phase 2: Data Transfer
Client sends data in numbered parts (base64-encoded):
Server Actions:
Validates
uploadIdexists and belongs to this userConverts base64
datatoUint8ArrayStores part in
MultipartUploadState.partsMapReturns acknowledgment:
Client repeats for parts 2, 3, 4, 5…
7.5.3 Phase 3: Finalization
Client sends finalization message with the actual request parameters:
{
"messageId": "upload-end-uuid",
"type": "multipartrequest",
"topic": "service:create_service",
"payload": {
"uploadId": "abc-123-def-456",
"part": "end",
"totalParts": 5,
"data": "",
"props": {
"tenant": "acme",
"service": "web",
"spec": {
"type": "bundle",
"bundleRef": "abc-123-def-456",
"comment": "Web service bundle"
}
}
}
}Server Actions:
Validates all parts received (count matches
totalParts)Combines parts in numerical order:
combinePartsInOrder()Writes complete file to object store:
/tmp/${userId}/${uploadId}Forwards request to target endpoint as normal
BusRequestExecutes handler with
bundleRefpointing to uploaded fileSchedules cleanup after 10 seconds (deletes temp file)
Returns normal operation response
Security:
Authorization validated once during initialization phase
Upload sessions isolated per user and connection
Temporary files stored in user-specific directories
Automatic cleanup prevents resource leaks
7.6 Rate Limiting
To prevent abuse and ensure fair resource allocation, the WebSocket API enforces rate limiting on incoming messages using a Leaky bucket algorithm.
Algorithm: Leaky Bucket (based on APISIX limit-req plugin)
Configuration Parameters:
rate: Requests per second allowed (e.g., 10)
burst: Maximum burst capacity (e.g., 20)
nodelay: Boolean flag
false: Traffic shaping (delay excess requests)true: Reject excess requests immediately
Rate Limit Calculation:
excess = max(excess - rate × elapsed + 1, 0)
delay = excess / rate
if (excess > burst) {
reject with HTTP 429
} else if (nodelay == false && delay > 0) {
sleep(delay) then process
} else {
process immediately
}
Message Size Limit:
Maximum message size: 1MB (1024 KB)
Oversized messages rejected with
_payload_too_large_errorMultipart protocol recommended for large payloads
Rate limits apply per connection, not per user. Connections are limited independently on each other.
7.8 Integration with REST API
The WebSocket API is fully complementary to the REST API, not a replacement. Both interfaces access the same business logic and provide consistent behavior.
When to Use Each:
REST API: Scripts, automation, command-line tools, simple integrations, operations where real-time updates aren’t needed. Axebow makes available a swagger definition of the web interface.
WebSocket API: Interactive dashboards, monitoring UIs, applications requiring immediate notification of changes, high-frequency operations
Both interfaces are first-class citizens in the Axebow platform, providing flexibility for diverse client requirements.