| name | objectstack-api | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| description | Design ObjectStack REST APIs, endpoints, service contracts, and integration protocols. Use when defining API routes, configuring authentication, setting up service discovery, or designing inter-service communication in an ObjectStack project. | ||||||||
| license | Apache-2.0 | ||||||||
| compatibility | Requires @objectstack/spec Zod schemas (v4+) | ||||||||
| metadata |
|
Expert instructions for designing REST APIs, service contracts, and integration protocols using the ObjectStack specification. This skill covers endpoint definitions, API discovery, authentication, dispatcher configuration, and inter-service communication patterns.
- You are defining custom REST API endpoints beyond auto-generated CRUD.
- You need to configure API authentication and authorization.
- You are setting up service discovery and health checks.
- You are designing inter-service communication (service-to-service calls).
- You need to understand the dispatcher routing system.
- You are integrating external APIs via datasource connectors.
Every ObjectStack object with apiEnabled: true (the default) automatically
gets a full REST API:
GET /api/v1/{object} # List records (with filter, sort, pagination)
GET /api/v1/{object}/:id # Get single record
POST /api/v1/{object} # Create record
PATCH /api/v1/{object}/:id # Update record
DELETE /api/v1/{object}/:id # Delete record (soft-delete if trash enabled)
POST /api/v1/{object}/bulk # Bulk operations
GET /api/v1/{object}/aggregate # Aggregation queries
Key rule: If your object defines
apiMethods, only those operations are exposed. For example,apiMethods: ['get', 'list']creates a read-only API.
For business logic beyond CRUD, define custom endpoints via the REST API plugin:
{
name: 'close_case',
path: '/api/v1/cases/:id/close',
method: 'POST',
description: 'Close a support case with resolution notes.',
handlerStatus: 'implemented',
request: {
params: { id: { type: 'string', required: true } },
body: {
resolution: { type: 'string', required: true },
satisfaction: { type: 'number', min: 1, max: 5 },
},
},
response: {
200: { description: 'Case closed successfully', schema: 'SupportCase' },
404: { description: 'Case not found' },
409: { description: 'Case already closed' },
},
auth: { required: true, permissions: ['support_agent'] },
}| Pattern | Use Case | Example |
|---|---|---|
/api/v1/{object} |
Auto-generated collection | /api/v1/accounts |
/api/v1/{object}/:id |
Auto-generated record | /api/v1/accounts/abc123 |
/api/v1/{object}/:id/{action} |
Custom action on record | /api/v1/cases/:id/close |
/api/v1/{domain}/{action} |
Domain-level action | /api/v1/ai/chat |
Rules:
- Always use plural nouns for collection paths (
accounts, notaccount). - Use snake_case for multi-word paths (
project_tasks, notprojectTasks). - Use verbs only for actions, not for CRUD (
/close,/approve). - Always prefix with
/api/v1/for versioning.
The full set of operations an object can expose:
| Method | HTTP | Purpose |
|---|---|---|
get |
GET /:id |
Retrieve a single record |
list |
GET / |
List records with filter/sort/pagination |
create |
POST / |
Create a new record |
update |
PATCH /:id |
Update an existing record |
delete |
DELETE /:id |
Delete a record |
upsert |
PUT / |
Create or update by external ID |
bulk |
POST /bulk |
Batch create/update/delete |
aggregate |
GET /aggregate |
Count, sum, avg, min, max |
history |
GET /:id/history |
Audit trail access |
search |
GET /search |
Full-text search |
restore |
POST /:id/restore |
Restore from trash |
purge |
DELETE /:id/purge |
Permanent deletion |
import |
POST /import |
Bulk data import |
export |
GET /export |
Data export |
ObjectStack services register themselves with the kernel and expose discovery metadata.
{
name: 'service-rest-api',
version: '1.0.0',
status: 'healthy', // 'healthy' | 'degraded' | 'unhealthy' | 'registered'
handlerReady: true, // HTTP handler verified and operational
endpoints: [
{ path: '/api/v1/accounts', methods: ['GET', 'POST'] },
{ path: '/api/v1/accounts/:id', methods: ['GET', 'PATCH', 'DELETE'] },
],
}Every ObjectStack deployment exposes /health:
{
"status": "healthy",
"version": "4.0.1",
"services": {
"objectql": { "status": "healthy" },
"rest-api": { "status": "healthy" },
"auth": { "status": "healthy" }
}
}The HttpDispatcher is the central request router in ObjectStack.
| HTTP Status | Error Type | When |
|---|---|---|
| 404 | ROUTE_NOT_FOUND |
No route matches the path |
| 405 | METHOD_NOT_ALLOWED |
Route exists but method not supported |
| 501 | NOT_IMPLEMENTED |
Route declared but handler is a stub |
| 503 | SERVICE_UNAVAILABLE |
Service is registered but not ready |
Every endpoint has a handler status:
| Status | Meaning |
|---|---|
implemented |
Handler is fully functional |
stub |
Handler exists but returns mock data |
planned |
Handler is defined in the spec but not yet coded |
Best practice: Always set
handlerStatusexplicitly. The dispatcher returns501 NOT_IMPLEMENTEDforstubandplannedhandlers, giving clear feedback to API consumers.
{
auth: {
required: true, // Require authentication
permissions: ['admin'], // Required permission profiles
rateLimit: {
requests: 100,
window: '1m', // per minute
},
},
}| Layer | Scope | Description |
|---|---|---|
| Authentication | Request | Who is the caller? (JWT, API key, OAuth) |
| RBAC | Object | Role-based access control (profile → permissions) |
| RLS | Record | Row-level security (visibility rules per record) |
| FLS | Field | Field-level security (hide/mask sensitive fields) |
Key rule: RBAC controls what objects/operations a user can access. RLS controls which records within those objects are visible. FLS controls which fields are readable/writable.
Connect to external data sources for virtualised data access:
{
name: 'legacy_erp',
type: 'sql',
driver: 'postgresql',
connection: {
host: 'erp.internal.example.com',
port: 5432,
database: 'erp_production',
ssl: true,
},
readOnly: true, // Safety for legacy systems
}| Driver | Use Case |
|---|---|
postgresql |
Primary production database |
mysql |
Legacy systems, WordPress integration |
sqlite |
Local development, embedded apps |
turso |
Edge SQLite (Turso/libSQL) — serverless |
memory |
Unit tests, development |
ObjectStack uses typed service contracts defined in @objectstack/spec/contracts:
// Service contract interface
interface DataService {
find(object: string, query: QueryOptions): Promise<Record[]>;
findOne(object: string, id: string): Promise<Record>;
create(object: string, data: object): Promise<Record>;
update(object: string, id: string, data: object): Promise<Record>;
delete(object: string, id: string): Promise<void>;
}Services are resolved through the microkernel:
const dataService = kernel.resolve<DataService>('data');
const authService = kernel.resolve<AuthService>('auth');
const aiService = kernel.resolve<AIService>('ai');- Version your APIs — always use
/api/v1/prefix. Breaking changes get a new version (v2). - Use auto-generated APIs whenever possible. Only create custom endpoints for business logic that cannot be expressed through CRUD + triggers.
- Return consistent error shapes. Use the
DispatcherErrorResponseSchemaformat withtype,message, andhint. - Document every endpoint with
descriptionand response schemas. - Set
handlerStatusto communicate implementation progress to consumers. - Apply least-privilege auth. Every endpoint should declare its required permissions explicitly.
- Use
upsertfor idempotent writes. External integrations should preferupsertovercreateto avoid duplicates.
- Exposing internal fields via API. Use FLS (field-level security) or
explicit
apiMethodsto restrict what is visible. - Missing pagination. Always paginate list endpoints. Default page size should be 20–50, with a max of 200.
- Not handling 409 Conflict. Concurrent updates should use optimistic
locking (version field) and return
409on conflict. - Ignoring rate limiting. Always configure rate limits for public and external-facing APIs.
- Using
DELETEfor soft-delete. ObjectStackDELETEperforms soft-delete whentrash: trueis enabled on the object. Do not implement soft-delete logic in custom endpoints — use the built-in mechanism.
- endpoint.zod.ts — Custom endpoint definitions
- auth.zod.ts — Auth providers, login types, session
- realtime.zod.ts — WebSocket/SSE subscriptions
- rest-server.zod.ts — REST server config, routing
- graphql.zod.ts — GraphQL schema, resolvers, subscriptions
- websocket.zod.ts — WebSocket protocol, channels, messages
- errors.zod.ts — Error response schemas, status codes
- batch.zod.ts — Batch operations, bulk request/response
- versioning.zod.ts — API versioning strategies, deprecation
- Schema index — All bundled schemas with dependency tree