Remote HTTP driver for ObjectQL - Universal client for browser, Node.js, and edge runtimes with DriverInterface v4.0 compliance
npm install @objectql/sdk> Remote HTTP Driver for ObjectQL - Universal client for browser, Node.js, and edge runtimes


The @objectql/sdk package provides a type-safe HTTP client for ObjectQL servers. It works seamlessly in browsers, Node.js, Deno, and edge runtimes like Cloudflare Workers.
---
* π Universal Runtime - Works in browsers, Node.js, Deno, and edge environments
* π¦ Zero Dependencies - Only depends on @objectql/types and @objectstack/spec for type definitions
* π Type-Safe - Full TypeScript support with generics
* π Modern APIs - Uses native fetch API available in all modern JavaScript runtimes
* π― RESTful Interface - Clean, predictable API design
* β
DriverInterface v4.0 - Fully compliant with ObjectStack protocol specification
* π Authentication - Built-in support for Bearer tokens and API keys
* π Retry Logic - Automatic retry with exponential backoff for network resilience
* π Request Logging - Optional request/response logging for debugging
---
``bash`
npm install @objectql/sdk @objectql/types
For frontend projects:
`bashUsing npm
npm install @objectql/sdk @objectql/types
---
π Quick Start
$3
`html
ObjectQL SDK Browser Example
ObjectQL Browser Client
`$3
`typescript
import { DataApiClient, MetadataApiClient } from '@objectql/sdk';// Initialize clients
const dataClient = new DataApiClient({
baseUrl: process.env.REACT_APP_API_URL || 'http://localhost:3000',
token: localStorage.getItem('auth_token')
});
const metadataClient = new MetadataApiClient({
baseUrl: process.env.REACT_APP_API_URL || 'http://localhost:3000'
});
// Use in your components
async function fetchUsers() {
const response = await dataClient.list('users', {
filter: [['status', '=', 'active']],
sort: [['created_at', 'desc']]
});
return response.items;
}
`$3
`javascript
const { DataApiClient } = require('@objectql/sdk');const client = new DataApiClient({
baseUrl: 'http://localhost:3000'
});
async function main() {
const users = await client.list('users');
console.log(users.items);
}
main();
`---
π API Reference
$3
Client for CRUD operations on data records.
#### Constructor
`typescript
new DataApiClient(config: DataApiClientConfig)
`Config Options:
*
baseUrl (string, required) - Base URL of the ObjectQL server
* token (string, optional) - Authentication token
* headers (Record, optional) - Additional HTTP headers
* timeout (number, optional) - Request timeout in milliseconds (default: 30000)#### Methods
#####
listList records with optional filtering, sorting, and pagination.
`typescript
const users = await client.list('users', {
filter: [['status', '=', 'active']],
sort: [['name', 'asc']],
limit: 20,
skip: 0,
fields: ['name', 'email', 'status']
});
`#####
getGet a single record by ID.
`typescript
const user = await client.get('users', 'user_123');
`#####
createCreate a new record.
`typescript
const newUser = await client.create('users', {
name: 'Alice',
email: 'alice@example.com',
status: 'active'
});
`#####
createManyCreate multiple records at once.
`typescript
const newUsers = await client.createMany('users', [
{ name: 'Bob', email: 'bob@example.com' },
{ name: 'Charlie', email: 'charlie@example.com' }
]);
`#####
updateUpdate an existing record.
`typescript
const updated = await client.update('users', 'user_123', {
status: 'inactive'
});
`#####
updateMany(objectName: string, request: DataApiBulkUpdateRequest): PromiseUpdate multiple records matching filters.
`typescript
await client.updateMany('users', {
filters: [['status', '=', 'pending']],
data: { status: 'active' }
});
`#####
delete(objectName: string, id: string | number): PromiseDelete a record by ID.
`typescript
await client.delete('users', 'user_123');
`#####
deleteMany(objectName: string, request: DataApiBulkDeleteRequest): PromiseDelete multiple records matching filters.
`typescript
await client.deleteMany('users', {
filters: [['created_at', '<', '2023-01-01']]
});
`#####
count(objectName: string, filters?: FilterExpression): PromiseCount records matching filters.
`typescript
const result = await client.count('users', [['status', '=', 'active']]);
console.log(result.count);
`---
$3
Client for reading object schemas and metadata.
#### Constructor
`typescript
new MetadataApiClient(config: MetadataApiClientConfig)
`#### Methods
#####
listObjects(): PromiseList all available objects.
`typescript
const objects = await metadataClient.listObjects();
`#####
getObject(objectName: string): PromiseGet detailed schema for an object.
`typescript
const userSchema = await metadataClient.getObject('users');
console.log(userSchema.fields);
`#####
getField(objectName: string, fieldName: string): PromiseGet metadata for a specific field.
`typescript
const emailField = await metadataClient.getField('users', 'email');
`#####
listActions(objectName: string): PromiseList actions available for an object.
`typescript
const actions = await metadataClient.listActions('users');
`---
$3
Client for connecting to a remote ObjectQL server via HTTP. Implements the standard
DriverInterface from @objectstack/spec.#### Constructor
`typescript
// Legacy constructor
new RemoteDriver(baseUrl: string, rpcPath?: string)// New config-based constructor (recommended)
new RemoteDriver(config: SdkConfig)
`Config Options:
*
baseUrl (string, required) - Base URL of the ObjectQL server
* rpcPath (string, optional) - JSON-RPC endpoint path (default: /api/objectql)
* queryPath (string, optional) - Query endpoint path (default: /api/query)
* commandPath (string, optional) - Command endpoint path (default: /api/command)
* executePath (string, optional) - Custom execute endpoint path (default: /api/execute)
* token (string, optional) - Authentication token (Bearer)
* apiKey (string, optional) - API key for authentication
* headers (Record, optional) - Custom HTTP headers
* timeout (number, optional) - Request timeout in milliseconds (default: 30000)
* enableRetry (boolean, optional) - Enable automatic retry on failure (default: false)
* maxRetries (number, optional) - Maximum retry attempts (default: 3)
* enableLogging (boolean, optional) - Enable request/response logging (default: false)#### Methods
#####
executeQuery(ast: QueryAST, options?: any): Promise<{ value: any[]; count?: number }>Execute a query using QueryAST format (DriverInterface v4.0).
`typescript
import { RemoteDriver } from '@objectql/sdk';const driver = new RemoteDriver({
baseUrl: 'http://localhost:3000',
token: 'your-auth-token',
enableRetry: true,
maxRetries: 3
});
// Execute a QueryAST
const result = await driver.executeQuery({
object: 'users',
fields: ['name', 'email', 'status'],
filters: {
type: 'comparison',
field: 'status',
operator: '=',
value: 'active'
},
sort: [{ field: 'created_at', order: 'desc' }],
top: 10,
skip: 0
});
console.log(result.value); // Array of users
console.log(result.count); // Total count
`#####
executeCommand(command: Command, options?: any): PromiseExecute a command for mutation operations (create, update, delete, bulk operations).
`typescript
// Create a record
const createResult = await driver.executeCommand({
type: 'create',
object: 'users',
data: {
name: 'Alice',
email: 'alice@example.com',
status: 'active'
}
});console.log(createResult.success); // true
console.log(createResult.data); // Created record
console.log(createResult.affected); // 1
// Update a record
const updateResult = await driver.executeCommand({
type: 'update',
object: 'users',
id: 'user_123',
data: { status: 'inactive' }
});
// Delete a record
const deleteResult = await driver.executeCommand({
type: 'delete',
object: 'users',
id: 'user_123'
});
// Bulk create
const bulkCreateResult = await driver.executeCommand({
type: 'bulkCreate',
object: 'users',
records: [
{ name: 'Bob', email: 'bob@example.com' },
{ name: 'Charlie', email: 'charlie@example.com' }
]
});
// Bulk update
const bulkUpdateResult = await driver.executeCommand({
type: 'bulkUpdate',
object: 'users',
updates: [
{ id: 'user_1', data: { status: 'active' } },
{ id: 'user_2', data: { status: 'inactive' } }
]
});
// Bulk delete
const bulkDeleteResult = await driver.executeCommand({
type: 'bulkDelete',
object: 'users',
ids: ['user_1', 'user_2', 'user_3']
});
`#####
execute(endpoint?: string, payload?: any, options?: any): PromiseExecute a custom operation on the remote server.
`typescript
// Execute a custom workflow
const workflowResult = await driver.execute('/api/workflows/approve', {
workflowId: 'wf_123',
comment: 'Approved by manager'
});// Use default execute endpoint
const customResult = await driver.execute(undefined, {
action: 'calculateMetrics',
params: { year: 2024, quarter: 'Q1' }
});
// Call a custom action
const actionResult = await driver.execute('/api/actions/send-email', {
to: 'user@example.com',
subject: 'Welcome',
body: 'Welcome to our platform!'
});
`#### Legacy CRUD Methods
The RemoteDriver also supports legacy CRUD methods for backward compatibility:
`typescript
// Find records
const users = await driver.find('users', {
filters: [['status', '=', 'active']],
sort: [['name', 'asc']],
limit: 10
});// Find one record
const user = await driver.findOne('users', 'user_123');
// Create a record
const newUser = await driver.create('users', {
name: 'Alice',
email: 'alice@example.com'
});
// Update a record
const updated = await driver.update('users', 'user_123', {
status: 'inactive'
});
// Delete a record
await driver.delete('users', 'user_123');
// Count records
const count = await driver.count('users', {
filters: [['status', '=', 'active']]
});
`$3
`typescript
// Bearer token authentication
const driverWithToken = new RemoteDriver({
baseUrl: 'http://localhost:3000',
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
});// API key authentication
const driverWithApiKey = new RemoteDriver({
baseUrl: 'http://localhost:3000',
apiKey: 'sk-1234567890abcdef'
});
// Both token and API key
const driverWithBoth = new RemoteDriver({
baseUrl: 'http://localhost:3000',
token: 'jwt-token',
apiKey: 'api-key'
});
// Custom headers
const driverWithHeaders = new RemoteDriver({
baseUrl: 'http://localhost:3000',
headers: {
'X-Tenant-ID': 'tenant_123',
'X-Request-ID': crypto.randomUUID()
}
});
`$3
`typescript
import { ObjectQLError, ApiErrorCode } from '@objectql/types';// Enable retry with exponential backoff
const driver = new RemoteDriver({
baseUrl: 'http://localhost:3000',
enableRetry: true,
maxRetries: 3,
timeout: 10000
});
try {
const result = await driver.executeQuery({ object: 'users' });
} catch (error) {
if (error instanceof ObjectQLError) {
switch (error.code) {
case ApiErrorCode.UNAUTHORIZED:
console.error('Authentication required');
break;
case ApiErrorCode.VALIDATION_ERROR:
console.error('Validation failed:', error.details);
break;
case ApiErrorCode.NOT_FOUND:
console.error('Resource not found');
break;
default:
console.error('API error:', error.message);
}
}
}
`$3
`typescript
// Enable logging for debugging
const driver = new RemoteDriver({
baseUrl: 'http://localhost:3000',
enableLogging: true
});// Logs will be printed to console:
// [RemoteDriver] executeQuery { endpoint: '...', ast: {...} }
// [RemoteDriver] executeQuery response { value: [...], count: 10 }
`---
π Browser Compatibility
The SDK uses modern JavaScript APIs available in all current browsers:
* fetch API - Available in all modern browsers
* Promises/async-await - ES2017+
* AbortSignal.timeout() - Chrome 103+, Firefox 100+, Safari 16.4+
$3
The SDK automatically includes a polyfill for
AbortSignal.timeout() that activates when running in older browsers. You don't need to add any polyfills manually - the SDK works universally out of the box!The polyfill is lightweight and only adds the missing functionality when needed, ensuring compatibility with:
- Chrome 90+
- Firefox 90+
- Safari 15+
- Edge 90+
For even older browsers, you may need to add polyfills for:
-
fetch API (via whatwg-fetch)
- AbortController (via abort-controller package)---
π§ Advanced Usage
$3
`typescript
const client = new DataApiClient({
baseUrl: 'http://localhost:3000',
headers: {
'X-Custom-Header': 'value',
'X-Request-ID': crypto.randomUUID()
}
});
`$3
`typescript
class AuthenticatedClient {
private client: DataApiClient; constructor(baseUrl: string) {
this.client = new DataApiClient({ baseUrl });
}
setToken(token: string) {
this.client = new DataApiClient({
baseUrl: this.client['baseUrl'],
token
});
}
async fetchData() {
return this.client.list('users');
}
}
`$3
`typescript
import { ObjectQLError, ApiErrorCode } from '@objectql/types';try {
await client.create('users', { email: 'invalid' });
} catch (error) {
if (error instanceof ObjectQLError) {
console.error('ObjectQL Error:', error.code, error.message);
if (error.code === ApiErrorCode.VALIDATION_ERROR) {
console.log('Validation failed:', error.details);
}
}
}
`---
π Examples
$3
`typescript
import { useState, useEffect } from 'react';
import { DataApiClient } from '@objectql/sdk';const client = new DataApiClient({
baseUrl: process.env.REACT_APP_API_URL
});
export function useObjectData(objectName: string, params?: any) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
setLoading(true);
const response = await client.list(objectName, params);
setData(response.items || []);
} catch (err) {
setError(err as Error);
} finally {
setLoading(false);
}
}
fetchData();
}, [objectName, JSON.stringify(params)]);
return { data, loading, error };
}
`$3
`typescript
import { ref, watchEffect } from 'vue';
import { DataApiClient } from '@objectql/sdk';const client = new DataApiClient({
baseUrl: import.meta.env.VITE_API_URL
});
export function useObjectData(objectName: string, params?: any) {
const data = ref([]);
const loading = ref(true);
const error = ref(null);
watchEffect(async () => {
try {
loading.value = true;
const response = await client.list(objectName, params);
data.value = response.items || [];
} catch (err) {
error.value = err as Error;
} finally {
loading.value = false;
}
});
return { data, loading, error };
}
`---
ποΈ Architecture
The SDK is designed with the ObjectQL "Trinity" architecture:
1. @objectql/types (The Contract) - Pure TypeScript interfaces
2. @objectql/sdk (The Client) - HTTP communication layer
3. ObjectQL Server (The Backend) - Data processing and storage
`
βββββββββββββββββββ
β Frontend β
β (Browser/App) β
β β
β @objectql/sdk β
ββββββββββ¬βββββββββ
β HTTP/REST
β
ββββββββββΌβββββββββ
β ObjectQL Server β
β β
β @objectql/core β
ββββββββββ¬βββββββββ
β
ββββββ΄βββββ
β SQL/Mongoβ
βββββββββββ
``---
MIT License - see LICENSE file for details.
---
* @objectql/types - TypeScript type definitions
* @objectql/core - Core ObjectQL engine
* @objectql/server - HTTP server implementation
---
We welcome contributions! Please see the main repository README for guidelines.
---
For complete documentation, visit:
* Client SDK Guide
* REST API Reference
* ObjectQL Documentation