Skip to content

Latest commit

 

History

History
540 lines (387 loc) · 15.6 KB

File metadata and controls

540 lines (387 loc) · 15.6 KB
title API Reference
description Complete REST API reference for ObjectStack — all endpoints, request/response schemas, and service availability.

API Reference

ObjectStack exposes a fully typed REST API. All endpoints use JSON request/response bodies. The API is service-driven — routes are only available when the corresponding plugin is installed. Use the Discovery endpoint to determine what services are available at runtime.

**Base URL**: Configurable, defaults to `/api/v1`. All paths below are relative to the base URL.

Discovery

The discovery endpoint is the entry point for all clients. It returns the API version, available routes, service capabilities, and per-service status.

GET /api/v1

Returns the full discovery manifest.

Response:

{
  "name": "ObjectOS",
  "version": "1.0.0",
  "environment": "development",
  "routes": {
    "data": "/api/v1/data",
    "metadata": "/api/v1/meta",
    "analytics": "/api/v1/analytics",
    "auth": null,
    "workflow": null
  },
  "features": {
    "graphql": false,
    "search": false,
    "websockets": false,
    "files": false,
    "analytics": true,
    "ai": false,
    "workflow": false,
    "notifications": false,
    "i18n": false
  },
  "services": {
    "metadata": {
      "enabled": true,
      "status": "degraded",
      "route": "/api/v1/meta",
      "provider": "kernel",
      "message": "In-memory registry; DB persistence pending"
    },
    "data": { "enabled": true, "status": "available", "route": "/api/v1/data", "provider": "kernel" },
    "analytics": { "enabled": true, "status": "available", "route": "/api/v1/analytics" },
    "auth": { "enabled": false, "status": "unavailable", "message": "Install an auth plugin to enable" }
  },
  "locale": {
    "default": "en",
    "supported": ["en", "zh-CN"],
    "timezone": "UTC"
  }
}

GET /.well-known/objectstack

Alias for the discovery endpoint used by auto-discovery in the client SDK.

**Service Status Values**: `available` (fully operational), `registered` (route declared but handler unverified — may return 501), `degraded` (partial functionality), `unavailable` (not installed), `stub` (placeholder that throws errors)

Metadata

Retrieve and manage object schemas, metadata types, and UI views. Always available — provided by the kernel.

GET /meta

List all registered metadata types.

Response: { types: ["object", "view", "plugin", ...] }

GET /meta/:type

List all items of a metadata type.

Parameter Location Description
type path Metadata type name (e.g. object, view)

Response: { type: "object", items: [{ name: "account", ... }, ...] }

GET /meta/:type/:name

Get a specific metadata item with optional ETag caching.

Parameter Location Description
type path Metadata type name
name path Item name (snake_case)
If-None-Match header ETag for conditional request

Response: { type: "object", name: "account", item: { ... } }
304 if ETag matches (not modified).

PUT /meta/:type/:name

Create or update a metadata item.

Body: { type: "object", name: "account", item: { ... } }
Response: { success: true }

GET /ui/view/:object/:type

Get an auto-generated UI view for an object.

Parameter Location Description
object path Object name (snake_case)
type path list or form

Response: Full ViewSchema definition with columns/fields derived from the object schema.


Data Operations

CRUD operations on any object. Always available — provided by the kernel.

GET /data/:object

Query records with filtering, sorting, selection, and pagination.

Parameter Location Description
object path Object name
select query Comma-separated field names
filter query Filter expression (JSON). filters also accepted for backward compatibility.
sort query Sort expression (e.g. name asc or -created_at)
top query Limit (default: 20)
skip query Offset
expand query Comma-separated list of relations to eager-load
search query Full-text search query

Note: OData-style $-prefixed parameters ($filter, $select, $orderby, $top, $skip) are supported via the OData endpoint. The standard REST API uses unprefixed parameter names.

Response:

{
  "object": "account",
  "records": [{ "id": "1", "name": "Acme Corp", ... }],
  "total": 42,
  "hasMore": true
}

GET /data/:object/:id

Get a single record by ID. Only select and expand query parameters are allowed; all other parameters are discarded.

Parameter Location Description
object path Object name
id path Record ID
select query Comma-separated field names to include
expand query Comma-separated list of relations to eager-load

Response: { object: "account", id: "1", record: { ... } }

POST /data/:object

Create a new record.

Body: { name: "Acme Corp", industry: "Technology" }
Response: { object: "account", id: "1", record: { ... } }

PATCH /data/:object/:id

Update an existing record (partial update).

Body: { industry: "Healthcare" }
Response: { object: "account", id: "1", record: { ... } }

DELETE /data/:object/:id

Delete a record.

Response: { object: "account", id: "1", success: true }


Batch Operations

Efficient bulk operations. Always available.

POST /data/:object/batch

Execute a batch operation (create / update / upsert / delete) on multiple records.

Body:

{
  "operation": "update",
  "records": [
    { "id": "1", "data": { "status": "active" } },
    { "id": "2", "data": { "status": "active" } }
  ],
  "options": {
    "atomic": true,
    "returnRecords": true,
    "continueOnError": false,
    "validateOnly": false
  }
}

Response: BatchUpdateResponse with succeeded, failed, total, and a per-record results array. Each entry in results has id, success, an optional errors array, and optional data (the full record, present when returnRecords is true).

POST /data/:object/createMany

Batch create multiple records.

Body: a bare array of records — [{ name: "A" }, { name: "B" }]. The REST handler reads the request body directly as the records array, so do not wrap it in { records: [...] }.
Response: { object: "account", records: [...], count: 2 }

POST /data/:object/updateMany

Batch update multiple records.

Body:

{
  "records": [
    { "id": "1", "data": { "status": "active" } },
    { "id": "2", "data": { "status": "closed" } }
  ],
  "options": { "atomic": false }
}

POST /data/:object/deleteMany

Batch delete records by ID list.

Body: { ids: ["1", "2", "3"] }


POST /data/:object/:id/clone

Clone a record. Reads the source, drops engine-owned columns (id, the audit fields, autonumbers, and computed formula/summary values) so they are re-derived, applies any caller overrides, and inserts the copy. Shallow by design — it duplicates the record's own fields, not its child records.

Gated by the object's enable.clone capability (default true); an object with enable.clone: false returns 403 CLONE_DISABLED.

Body (optional): { "overrides": { "name": "Acme (Copy)" } } — applied on top of the copied values (a bare field map is also accepted). The natural place to set a new name or clear a unique field.

Response 201: { object, id, sourceId, record }


Analytics

Semantic BI queries using a cube-style API. Available when the analytics service is enabled.

POST /analytics/query

Execute an analytics query.

Body:

{
  "cube": "account",
  "measures": ["revenue.sum", "count"],
  "dimensions": ["industry"],
  "where": { "status": "active" },
  "limit": 100
}
Filtering uses the canonical Query DSL `where` object (the same MongoDB-style `FilterCondition` accepted by `find()`), not a `filters` array.

Response: the runtime dispatcher wraps the AnalyticsResult as { success: true, data: { rows, fields, sql?, totals? } }:

{
  "success": true,
  "data": {
    "rows": [
      { "industry": "Technology", "revenue.sum": 150000, "count": 5 },
      { "industry": "Healthcare", "revenue.sum": 80000, "count": 3 }
    ],
    "fields": [
      { "name": "industry", "type": "string", "label": "Industry" },
      { "name": "revenue.sum", "type": "number", "label": "Revenue Sum", "format": "$0,0" },
      { "name": "count", "type": "number", "label": "Count" }
    ],
    "sql": "SELECT ..."
  }
}

GET /analytics/meta

Get auto-generated cube metadata for all objects.

Response: Array of cube definitions with measures, dimensions, and time dimensions.

POST /analytics/sql

Execute a raw SQL analytics query (if supported by driver).


Package Management

Manage installed plugins/packages.

GET /packages

List installed packages.

POST /packages

Install a package from manifest.

Body: { manifest: { name: "plugin-auth", version: "1.0.0", ... } }

GET /packages/:id

Get package details.

DELETE /packages/:id

Uninstall a package.

PATCH /packages/:id/enable

Enable a disabled package.

PATCH /packages/:id/disable

Disable a package without uninstalling.


Authentication (Plugin Required)

These endpoints are only available when an auth plugin is installed. Check `discovery.services.auth.enabled` first.

POST /auth/login

Authenticate and receive a session token.

Body: { username: "admin", password: "secret" }
Response: { token: "jwt...", expiresAt: "...", user: { ... } }


Plugin-Provided Service Endpoints

The following endpoints become available when the corresponding plugin is installed and registered with the kernel. Use the discovery services map to check availability.

Workflow (/workflow) — Plugin Required

Method Endpoint Description
GET /workflow/:object/config Get workflow configuration
GET /workflow/:object/:recordId/state Get record's workflow state
POST /workflow/:object/:recordId/transition Execute state transition
POST /workflow/:object/:recordId/approve Approve workflow step
POST /workflow/:object/:recordId/reject Reject workflow step

Automation (/automation) — Plugin Required

Method Endpoint Description
POST /automation/trigger/:name Trigger an automation flow by name

Views (/ui) — Plugin Required

Method Endpoint Description
GET /ui/views?object=:object List views for an object
GET /ui/views/:viewId Get a view definition
POST /ui/views Create a new view
PATCH /ui/views/:viewId Update a view
DELETE /ui/views/:viewId Delete a view

Realtime (/realtime) — Plugin Required

Method Endpoint Description
POST /realtime/connect Establish WebSocket/SSE connection
POST /realtime/disconnect Close connection
POST /realtime/subscribe Subscribe to channel
POST /realtime/unsubscribe Unsubscribe
POST /realtime/presence Set presence
GET /realtime/presence/:channel Get channel presence

Notifications (/notifications) — Plugin Required

Method Endpoint Description
GET /notifications List notifications (inbox)
POST /notifications/read Mark notifications as read (body: { ids: string[] })
POST /notifications/read/all Mark all as read
The core dispatcher implements only the list / read / read-all routes above. Device-registration and preference endpoints are provided by specific notification plugins, if any.

AI (/ai) — Plugin Required

Method Endpoint Description
POST /ai/nlq Natural language → query
POST /ai/chat AI chat conversation
POST /ai/suggest Get value suggestions
POST /ai/insights Get data insights

i18n (/i18n) — Plugin Required

Method Endpoint Description
GET /i18n/locales List available locales
GET /i18n/translations/:locale Get translation bundle
GET /i18n/labels/:object/:locale Get field labels

GraphQL (/graphql) — Plugin Required

Method Endpoint Description
POST /graphql Execute GraphQL query/mutation

File Storage (/storage) — Plugin Required

Method Endpoint Description
POST /storage/upload Upload a file
GET /storage/file/:id Download a file

Error Handling

Error responses depend on which HTTP server is in front of the kernel. There are two wire formats in use today.

Kernel REST server (@objectstack/rest) emits a string error message plus a SCREAMING_SNAKE code:

{
  "error": "Record not found: account/123",
  "code": "RECORD_NOT_FOUND"
}

Validation failures additionally include an issues array. Common codes emitted by the kernel REST server:

Code HTTP Description
VALIDATION_FAILED 400 Input validation failed (includes issues)
PERMISSION_DENIED 403 Insufficient permissions
RECORD_NOT_FOUND 404 Resource does not exist
CONCURRENT_UPDATE 409 Record was modified by another user

Runtime dispatcher (@objectstack/runtime) wraps errors in the { success: false, ... } envelope, where code is the numeric HTTP status:

{
  "success": false,
  "error": {
    "message": "Record not found: account/123",
    "code": 404,
    "details": {}
  }
}
The richer `ErrorResponseSchema` in `@objectstack/spec/api` (with `category`, `retryable`, etc.) is the aspirational spec envelope, not the current wire format. Its `category` values are drawn from the `ErrorCategory` enum: `validation`, `authentication`, `authorization`, `not_found`, `conflict`, `rate_limit`, `server`, `external`, `maintenance`.

Protocol Types (Zod)

All request/response schemas are defined as Zod schemas in @objectstack/spec/api and can be used for both runtime validation and TypeScript type inference.

import { 
  FindDataRequestSchema, 
  FindDataResponseSchema,
  type FindDataRequest,
  type FindDataResponse,
} from '@objectstack/spec/api';

// Runtime validation
const request = FindDataRequestSchema.parse({ object: 'account', query: { ... } });

// TypeScript type
const response: FindDataResponse = await protocol.findData(request);

See the Protocol Reference for the full list of protocol methods and their Zod schemas.


Next Steps