Performance Optimization
Performance Optimization
1. Batch Requests
When possible, batch multiple operations using elementIds arrays:
// Batch read current values for multiple objects
const batchReadObjects = async (token, elementIds) => {
const response = await fetch('https://api.i3x.dev/v1/objects/value', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
elementIds: elementIds,
maxDepth: 1 // Control recursion depth
})
});
const data = await response.json();
return data.results;
};
// Batch read object metadata
const batchGetObjects = async (token, elementIds) => {
const response = await fetch('https://api.i3x.dev/v1/objects/list', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ elementIds })
});
const data = await response.json();
return data.results;
};
2. Control Recursion Depth
Use the maxDepth parameter to limit data retrieval for compositional hierarchies:
const getObjectWithChildren = async (token, elementIds, depth = 1) => {
const response = await fetch('https://api.i3x.dev/v1/objects/value', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
elementIds: elementIds,
maxDepth: depth // 0 = infinite, 1 = no child recursion, 2+ = limited depth
})
});
// Check for HTTP 206 — server hit its own depth limit
const isPartial = response.status === 206;
const data = await response.json();
return { results: data.results, isPartial };
};
3. Time-Bounded Historical Queries
When querying historical data, always specify time bounds to limit result size:
const getHistoricalData = async (token, elementIds, startTime, endTime) => {
const response = await fetch('https://api.i3x.dev/v1/objects/history', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
elementIds: elementIds,
startTime: startTime, // RFC 3339 format
endTime: endTime,
maxDepth: 1
})
});
const data = await response.json();
return data.results;
};
4. Prefer Sync over Stream for Reliability
For applications where data loss is unacceptable, use the sync endpoint instead of SSE streaming. Sync uses sequence numbers to guarantee delivery even if the client crashes:
// Reliable polling with sequence number acknowledgment
const pollSubscription = async (token, subscriptionId, lastSequence = 0) => {
const response = await fetch('https://api.i3x.dev/v1/subscriptions/sync', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
subscriptionId: subscriptionId,
acknowledgeSequence: lastSequence
})
});
const data = await response.json();
return data.result; // Contains updates and new sequenceNumber
};
5. Cache Static Data Aggressively
Namespaces, object types, and relationship types change rarely. Cache them with a long TTL:
const TYPE_CACHE_TTL = 300000; // 5 minutes
const getCachedObjectTypes = (() => {
let cache = null;
let cacheTime = 0;
return async (token) => {
if (cache && Date.now() - cacheTime < TYPE_CACHE_TTL) {
return cache;
}
const response = await fetch('https://api.i3x.dev/v1/objecttypes', {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
cache = data.result;
cacheTime = Date.now();
return cache;
};
})();