The primary ObjectQL API is a JSON-RPC style protocol where all operations are sent to a single endpoint.
POST /api/objectql
Content-Type: application/json
interface ObjectQLRequest {
// Authentication context (optional, can also come from headers)
user ?: {
id : string ;
roles : string [];
[ key : string ] : any ;
};
// The operation to perform
op : 'find' | 'findOne' | 'create' | 'update' | 'delete' | 'count' | 'action' | 'createMany' | 'updateMany' | 'deleteMany' ;
// The target object/table
object : string ;
// Operation-specific arguments
args : any ;
}
interface ObjectQLResponse {
// For list operations (find)
items ?: any [];
// Pagination metadata (for list operations)
meta ?: {
total : number ; // Total number of records
page ?: number ; // Current page number (1-indexed)
size ?: number ; // Number of items per page
pages ?: number ; // Total number of pages
has_next ?: boolean ; // Whether there is a next page
};
// For single item operations, the response is the object itself with '@type' field
// Examples: findOne, create, update return { id: '...', name: '...', '@type': 'users' }
'@type' ?: string ; // Object type identifier
// Error information
error ?: {
code : string ;
message : string ;
details ?: any ;
};
// Other fields from the actual data object (for single item responses)
[ key : string ] : any ;
}
Retrieve multiple records with filtering, sorting, pagination, and joins.
Request:
{
"op" : "find" ,
"object" : "orders" ,
"args" : {
"fields" : [ "order_no" , "amount" , "status" , "created_at" ],
"filters" : [
[ "status" , "=" , "paid" ],
"and" ,
[ "amount" , ">" , 1000 ]
],
"sort" : [[ "created_at" , "desc" ]],
"top" : 20 ,
"skip" : 0 ,
"expand" : {
"customer" : {
"fields" : [ "name" , "email" ]
}
}
}
}
Response:
{
"items" : [
{
"order_no" : "ORD-001" ,
"amount" : 1500 ,
"status" : "paid" ,
"created_at" : "2024-01-15T10:30:00Z" ,
"customer" : {
"name" : "Acme Corp" ,
"email" : "contact@acme.com"
}
}
],
"meta" : {
"total" : 150 ,
"page" : 1 ,
"size" : 20 ,
"pages" : 8 ,
"has_next" : true
}
}
Retrieve a single record by ID or query.
Request (by ID):
{
"op" : "findOne" ,
"object" : "users" ,
"args" : "user_123"
}
Request (by query):
{
"op" : "findOne" ,
"object" : "users" ,
"args" : {
"filters" : [[ "email" , "=" , "alice@example.com" ]]
}
}
Response:
{
"id" : "user_123" ,
"name" : "Alice" ,
"email" : "alice@example.com" ,
"@type" : "users"
}
Insert a new record.
Request:
{
"op" : "create" ,
"object" : "tasks" ,
"args" : {
"name" : "Review PR" ,
"priority" : "high" ,
"assignee_id" : "user_123" ,
"due_date" : "2024-01-20"
}
}
Response:
{
"id" : "task_456" ,
"name" : "Review PR" ,
"priority" : "high" ,
"assignee_id" : "user_123" ,
"due_date" : "2024-01-20" ,
"created_at" : "2024-01-15T10:30:00Z" ,
"@type" : "tasks"
}
Modify an existing record.
Request:
{
"op" : "update" ,
"object" : "tasks" ,
"args" : {
"id" : "task_456" ,
"data" : {
"status" : "completed" ,
"completed_at" : "2024-01-16T14:00:00Z"
}
}
}
Response:
{
"id" : "task_456" ,
"status" : "completed" ,
"completed_at" : "2024-01-16T14:00:00Z" ,
"@type" : "tasks"
}
Remove a record by ID.
Request:
{
"op" : "delete" ,
"object" : "tasks" ,
"args" : {
"id" : "task_456"
}
}
Response:
{
"id" : "task_456" ,
"deleted" : true ,
"@type" : "tasks"
}
Get the count of records matching a filter.
Request:
{
"op" : "count" ,
"object" : "orders" ,
"args" : {
"filters" : [
[ "status" , "=" , "pending" ]
]
}
}
Response:
{
"count" : 42 ,
"@type" : "orders"
}
Execute a custom server-side action (RPC-style operation).
Request:
{
"op" : "action" ,
"object" : "orders" ,
"args" : {
"action" : "approve" ,
"id" : "order_789" ,
"input" : {
"approved_by" : "manager_123" ,
"notes" : "Approved for expedited shipping"
}
}
}
Response:
{
"success" : true ,
"message" : "Order approved successfully" ,
"order" : {
"id" : "order_789" ,
"status" : "approved" ,
"approved_at" : "2024-01-15T10:30:00Z"
},
"@type" : "orders"
}
ObjectQL supports efficient bulk operations for creating, updating, and deleting multiple records in a single request.
Important Notes:
Validation & Hooks : Bulk operations process each record individually to ensure validation rules and hooks (beforeCreate, afterCreate, etc.) are properly executed, maintaining data integrity
Atomicity : Operations are not atomic by default - if one record fails, others may have already been processed
Performance : While bulk operations are more efficient than separate API calls, they may be slower than driver-level bulk operations due to individual validation/hook execution
Use Cases : Use bulk operations when you need consistent validation and business logic enforcement. For high-performance batch imports where validation is already handled, consider using driver-level operations directly
Insert multiple records in a single operation.
Request:
{
"op" : "createMany" ,
"object" : "tasks" ,
"args" : [
{
"name" : "Task 1" ,
"priority" : "high" ,
"assignee_id" : "user_123"
},
{
"name" : "Task 2" ,
"priority" : "medium" ,
"assignee_id" : "user_456"
},
{
"name" : "Task 3" ,
"priority" : "low" ,
"assignee_id" : "user_789"
}
]
}
Response:
{
"items" : [
{
"id" : "task_101" ,
"name" : "Task 1" ,
"priority" : "high" ,
"assignee_id" : "user_123" ,
"created_at" : "2024-01-15T10:30:00Z"
},
{
"id" : "task_102" ,
"name" : "Task 2" ,
"priority" : "medium" ,
"assignee_id" : "user_456" ,
"created_at" : "2024-01-15T10:30:00Z"
},
{
"id" : "task_103" ,
"name" : "Task 3" ,
"priority" : "low" ,
"assignee_id" : "user_789" ,
"created_at" : "2024-01-15T10:30:00Z"
}
],
"count" : 3 ,
"@type" : "tasks"
}
Update all records matching a filter.
Request:
{
"op" : "updateMany" ,
"object" : "tasks" ,
"args" : {
"filters" : {
"status" : "pending" ,
"priority" : "low"
},
"data" : {
"status" : "cancelled" ,
"cancelled_at" : "2024-01-15T10:30:00Z"
}
}
}
Response:
{
"count" : 15 ,
"@type" : "tasks"
}
Delete all records matching a filter.
Request:
{
"op" : "deleteMany" ,
"object" : "tasks" ,
"args" : {
"filters" : {
"status" : "completed" ,
"completed_at" : [ "<" , "2023-01-01" ]
}
}
}
Response:
{
"count" : 42 ,
"@type" : "tasks"
}
Error Handling Example:
// If a record fails validation during bulk operation
{
"error" : {
"code" : "VALIDATION_ERROR" ,
"message" : "Validation failed" ,
"details" : {
"fields" : {
"priority" : "Invalid priority value"
}
}
}
}
Add semantic information to queries for better logging, debugging, and AI processing:
{
"op" : "find" ,
"object" : "projects" ,
"ai_context" : {
"intent" : "Find at-risk projects requiring immediate attention" ,
"natural_language" : "Show active projects that are overdue or over budget" ,
"use_case" : "Project manager dashboard"
},
"args" : {
"filters" : [
[ "status" , "=" , "active" ],
"and" ,
[
[ "end_date" , "<" , "$today" ],
"or" ,
[ "actual_cost" , ">" , "budget" ]
]
]
}
}
Perform GROUP BY operations:
{
"op" : "find" ,
"object" : "orders" ,
"args" : {
"groupBy" : [ "category" ],
"aggregate" : [
{
"func" : "sum" ,
"field" : "amount" ,
"alias" : "total_sales"
},
{
"func" : "count" ,
"field" : "id" ,
"alias" : "order_count"
}
],
"filters" : [[ "status" , "=" , "paid" ]],
"sort" : [[ "total_sales" , "desc" ]]
}
}