Common Use Cases
Overview
This guide provides production-ready code examples for common Q01 Core API use cases. Each pattern includes complete implementation with error handling, performance optimization, and best practices.
Covered Use Cases:
- Product Catalog Management
- Order Processing Workflow
- Customer Data Management
- Inventory Synchronization
- Multi-Tenant Application
- Real-Time Dashboard
- Data Migration Project
- External System Integration
Use Case 1: Product Catalog Management
Scenario
E-commerce application managing product catalog with categories, prices, and inventory.
Implementation
class ProductCatalogService {
constructor(coreAPI) {
this.coreAPI = coreAPI;
this.cache = new Map();
}
// Get products by category with caching
async getProductsByCategory(categoryId, page = 1, limit = 20) {
const cacheKey = `category:${categoryId}:${page}:${limit}`;
// Check cache
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < 300000) { // 5 minutes
return cached.data;
}
}
// Fetch from API
const response = await this.coreAPI.get('/api/v4/core/products', {
params: {
filters: `XPRD05:eq:${categoryId},TREC:eq:N,XPRD06:eq:Y`,
fields: 'PRD_ID,XPRD01,XPRD02,XPRD03,XPRD04,XPRD05',
order_by: 'XPRD01',
limit: limit,
offset: (page - 1) * limit
}
});
// Cache result
this.cache.set(cacheKey, {
data: response.data,
timestamp: Date.now()
});
return response.data;
}
// Create product with validation
async createProduct(productData) {
// Validate required fields
const required = ['XPRD01', 'XPRD02', 'XPRD05'];
for (const field of required) {
if (!productData[field]) {
throw new Error(`Missing required field: ${field}`);
}
}
// Set defaults
productData.XPRD06 = productData.XPRD06 || 'Y'; // Active by default
productData.TREC = 'N'; // New record
try {
const response = await this.coreAPI.post('/api/v4/core/products', productData);
// Invalidate category cache
this.invalidateCategoryCache(productData.XPRD05);
return response.data;
} catch (error) {
console.error('Failed to create product:', error);
throw error;
}
}
// Update product price
async updatePrice(productId, newPrice) {
const response = await this.coreAPI.patch(`/api/v4/core/products/${productId}`, {
XPRD02: newPrice
});
// Invalidate product cache
this.cache.delete(`product:${productId}`);
return response.data;
}
// Bulk price update
async bulkUpdatePrices(updates) {
const batchSize = 100;
const batches = this.chunk(updates, batchSize);
for (const batch of batches) {
await this.coreAPI.put('/api/v4/core/products/batch', {
records: batch
});
}
// Clear all caches
this.cache.clear();
}
// Search products
async searchProducts(query, filters = {}) {
const response = await this.coreAPI.get('/api/v4/core/products', {
params: {
search: query,
filters: this.buildFilters(filters),
fields: 'PRD_ID,XPRD01,XPRD02,XPRD03,XPRD04',
limit: 50
}
});
return response.data;
}
buildFilters(filters) {
const parts = ['TREC:eq:N'];
if (filters.category) parts.push(`XPRD05:eq:${filters.category}`);
if (filters.active !== undefined) parts.push(`XPRD06:eq:${filters.active ? 'Y' : 'N'}`);
if (filters.minPrice) parts.push(`XPRD02:gte:${filters.minPrice}`);
if (filters.maxPrice) parts.push(`XPRD02:lte:${filters.maxPrice}`);
return parts.join(',');
}
invalidateCategoryCache(categoryId) {
for (const [key, value] of this.cache.entries()) {
if (key.startsWith(`category:${categoryId}:`)) {
this.cache.delete(key);
}
}
}
chunk(array, size) {
const chunks = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
}
// Usage
const catalogService = new ProductCatalogService(coreAPIClient);
// Get products by category
const products = await catalogService.getProductsByCategory(5, 1, 20);
// Create new product
const newProduct = await catalogService.createProduct({
XPRD01: 'Widget Pro 2024',
XPRD02: 49.99,
XPRD03: 'WGT-2024-001',
XPRD04: 'widget-pro-2024',
XPRD05: 5,
XPRD06: 'Y'
});
// Update price
await catalogService.updatePrice(123, 44.99);
// Bulk update
await catalogService.bulkUpdatePrices([
{PRD_ID: 123, XPRD02: 44.99},
{PRD_ID: 124, XPRD02: 54.99},
{PRD_ID: 125, XPRD02: 64.99}
]);
// Search
const results = await catalogService.searchProducts('widget', {
category: 5,
minPrice: 20,
maxPrice: 100
});
Use Case 2: Order Processing Workflow
Scenario
Handle complete order lifecycle from creation to fulfillment.
Implementation
class OrderProcessingService {
constructor(coreAPI, eventBus) {
this.coreAPI = coreAPI;
this.eventBus = eventBus;
}
// Create order with line items
async createOrder(orderData) {
try {
// 1. Create order header
const order = await this.coreAPI.post('/api/v4/core/orders', {
XORD_CUSTOMER_ID: orderData.customerId,
XORD_DATE: new Date().toISOString(),
XORD_STATUS: 'PENDING',
XORD_TOTAL: orderData.total,
TREC: 'N'
});
// 2. Create order lines
for (const item of orderData.items) {
await this.coreAPI.post('/api/v4/core/order_lines', {
XORDLN_ORDER_ID: order.ORD_ID,
XORDLN_PRODUCT_ID: item.productId,
XORDLN_QUANTITY: item.quantity,
XORDLN_PRICE: item.price,
XORDLN_TOTAL: item.quantity * item.price,
TREC: 'N'
});
}
// 3. Reserve inventory
await this.reserveInventory(orderData.items);
// 4. Emit event
this.eventBus.emit('order.created', {
orderId: order.ORD_ID,
customerId: orderData.customerId,
total: orderData.total
});
return order;
} catch (error) {
console.error('Failed to create order:', error);
throw error;
}
}
// Update order status
async updateOrderStatus(orderId, newStatus) {
const order = await this.coreAPI.patch(`/api/v4/core/orders/${orderId}`, {
XORD_STATUS: newStatus,
XORD_UPDATED_AT: new Date().toISOString()
});
// Emit status change event
this.eventBus.emit('order.status_changed', {
orderId: orderId,
oldStatus: order.XORD_STATUS,
newStatus: newStatus
});
// Handle status-specific actions
switch (newStatus) {
case 'CONFIRMED':
await this.processPayment(orderId);
break;
case 'SHIPPED':
await this.sendShippingNotification(orderId);
break;
case 'DELIVERED':
await this.completeOrder(orderId);
break;
case 'CANCELLED':
await this.releaseInventory(orderId);
break;
}
return order;
}
// Get order with details
async getOrderDetails(orderId) {
// Get order header
const order = await this.coreAPI.get(`/api/v4/core/orders/${orderId}`, {
params: {
expand: 'XORD_CUSTOMER_ID'
}
});
// Get order lines
const lines = await this.coreAPI.get('/api/v4/core/order_lines', {
params: {
filters: `XORDLN_ORDER_ID:eq:${orderId}`,
expand: 'XORDLN_PRODUCT_ID'
}
});
return {
...order.data,
lines: lines.data
};
}
// Reserve inventory
async reserveInventory(items) {
for (const item of items) {
await this.coreAPI.patch(`/api/v4/core/inventory/${item.productId}`, {
XINV_RESERVED: {$inc: item.quantity}
});
}
}
// Release inventory
async releaseInventory(orderId) {
const lines = await this.coreAPI.get('/api/v4/core/order_lines', {
params: {
filters: `XORDLN_ORDER_ID:eq:${orderId}`
}
});
for (const line of lines.data) {
await this.coreAPI.patch(`/api/v4/core/inventory/${line.XORDLN_PRODUCT_ID}`, {
XINV_RESERVED: {$inc: -line.XORDLN_QUANTITY}
});
}
}
async processPayment(orderId) {
// Payment processing logic
console.log(`Processing payment for order ${orderId}`);
}
async sendShippingNotification(orderId) {
// Shipping notification logic
console.log(`Sending shipping notification for order ${orderId}`);
}
async completeOrder(orderId) {
// Order completion logic
console.log(`Completing order ${orderId}`);
}
}
// Usage
const orderService = new OrderProcessingService(coreAPIClient, eventBus);
// Create order
const order = await orderService.createOrder({
customerId: 456,
items: [
{productId: 123, quantity: 2, price: 29.99},
{productId: 124, quantity: 1, price: 49.99}
],
total: 109.97
});
// Update status
await orderService.updateOrderStatus(order.ORD_ID, 'CONFIRMED');
await orderService.updateOrderStatus(order.ORD_ID, 'SHIPPED');
await orderService.updateOrderStatus(order.ORD_ID, 'DELIVERED');
// Get details
const details = await orderService.getOrderDetails(order.ORD_ID);
Use Case 3: Multi-Tenant Application
Scenario
SaaS application serving multiple tenants with data isolation.
Implementation
class TenantService {
constructor(coreAPI) {
this.coreAPI = coreAPI;
}
// Set tenant context for all requests
setTenantContext(tenantId, userId, peso = 3) {
this.context = {
source: tenantId,
peso: peso,
ambiente: 'P',
centro_dett: 'HQ',
modulo: 'app',
lingua: 'IT'
};
// Add interceptor to include context in all requests
this.coreAPI.interceptors.request.use(config => {
config.headers['X-Source'] = this.context.source;
config.headers['X-Peso'] = this.context.peso;
config.headers['X-Ambiente'] = this.context.ambiente;
config.headers['X-Centro-Dett'] = this.context.centro_dett;
return config;
});
}
// Get tenant-specific data
async getTenantData(dimension, filters = {}) {
// Context automatically applied via interceptor
const response = await this.coreAPI.get(`/api/v4/core/${dimension}`, {
params: {
filters: this.buildFilters(filters),
limit: 100
}
});
return response.data;
}
// Create tenant-specific record
async createTenantRecord(dimension, data) {
// source automatically set from context
const response = await this.coreAPI.post(`/api/v4/core/${dimension}`, {
...data,
TREC: 'N'
});
return response.data;
}
// Tenant analytics
async getTenantMetrics() {
const [products, orders, customers] = await Promise.all([
this.getTenantData('products', {active: true}),
this.getTenantData('orders', {status: 'CONFIRMED'}),
this.getTenantData('customers', {active: true})
]);
return {
totalProducts: products.total,
totalOrders: orders.total,
totalCustomers: customers.total,
activeProducts: products.data.filter(p => p.XPRD06 === 'Y').length
};
}
buildFilters(filters) {
const parts = ['TREC:eq:N'];
if (filters.active !== undefined) {
// Dimension-specific active field
parts.push(`XPRD06:eq:${filters.active ? 'Y' : 'N'}`);
}
if (filters.status) {
parts.push(`XORD_STATUS:eq:${filters.status}`);
}
return parts.join(',');
}
}
// Usage per tenant
const tenantService = new TenantService(coreAPIClient);
// Tenant A session
tenantService.setTenantContext('tenant_a', 'user_1', 3);
const tenantAProducts = await tenantService.getTenantData('products');
// Only sees tenant_a products
// Tenant B session
tenantService.setTenantContext('tenant_b', 'user_2', 3);
const tenantBProducts = await tenantService.getTenantData('products');
// Only sees tenant_b products (complete isolation)
// Analytics
const metrics = await tenantService.getTenantMetrics();
console.log(metrics);
Use Case 4: Real-Time Dashboard
Scenario
Admin dashboard with real-time metrics and updates.
Implementation
class DashboardService {
constructor(coreAPI, websocket) {
this.coreAPI = coreAPI;
this.websocket = websocket;
this.metrics = new Map();
this.subscribers = new Set();
}
// Initialize dashboard
async initialize() {
// Load initial metrics
await this.refreshMetrics();
// Subscribe to real-time updates (OUTBOX events)
this.websocket.on('ProductCreated', () => this.refreshMetrics());
this.websocket.on('OrderCreated', () => this.refreshMetrics());
this.websocket.on('CustomerCreated', () => this.refreshMetrics());
// Periodic refresh (every 30 seconds)
setInterval(() => this.refreshMetrics(), 30000);
}
async refreshMetrics() {
try {
const [products, orders, revenue, customers] = await Promise.all([
this.getProductMetrics(),
this.getOrderMetrics(),
this.getRevenueMetrics(),
this.getCustomerMetrics()
]);
const metrics = {
products,
orders,
revenue,
customers,
timestamp: Date.now()
};
this.metrics.set('dashboard', metrics);
// Notify subscribers
this.notifySubscribers(metrics);
return metrics;
} catch (error) {
console.error('Failed to refresh metrics:', error);
throw error;
}
}
async getProductMetrics() {
const response = await this.coreAPI.get('/api/v4/core/products', {
params: {
filters: 'TREC:eq:N',
aggregate: 'count',
group_by: 'XPRD05'
}
});
return {
total: response.total,
active: response.data.filter(p => p.XPRD06 === 'Y').length,
byCategory: response.data
};
}
async getOrderMetrics() {
const response = await this.coreAPI.get('/api/v4/core/orders', {
params: {
filters: 'TREC:eq:N',
aggregate: 'count,sum:XORD_TOTAL',
group_by: 'XORD_STATUS'
}
});
return {
total: response.total,
byStatus: response.data
};
}
async getRevenueMetrics() {
const today = new Date().toISOString().split('T')[0];
const response = await this.coreAPI.get('/api/v4/core/orders', {
params: {
filters: `TREC:eq:N,XORD_STATUS:eq:CONFIRMED,XORD_DATE:gte:${today}`,
aggregate: 'sum:XORD_TOTAL'
}
});
return {
today: response.aggregates.sum_XORD_TOTAL || 0
};
}
async getCustomerMetrics() {
const response = await this.coreAPI.get('/api/v4/core/customers', {
params: {
filters: 'TREC:eq:N',
aggregate: 'count'
}
});
return {
total: response.total
};
}
// Subscribe to metric updates
subscribe(callback) {
this.subscribers.add(callback);
// Return unsubscribe function
return () => this.subscribers.delete(callback);
}
notifySubscribers(metrics) {
for (const callback of this.subscribers) {
try {
callback(metrics);
} catch (error) {
console.error('Subscriber error:', error);
}
}
}
}
// Usage
const dashboardService = new DashboardService(coreAPIClient, websocket);
// Initialize
await dashboardService.initialize();
// Subscribe to updates
const unsubscribe = dashboardService.subscribe((metrics) => {
console.log('Dashboard updated:', metrics);
updateUI(metrics);
});
// Get current metrics
const metrics = dashboardService.metrics.get('dashboard');
Use Case 5: Data Migration
Scenario
Migrate data from legacy system to Q01 Core APIs.
Implementation
class DataMigrationService {
constructor(coreAPI, legacyDB) {
this.coreAPI = coreAPI;
this.legacyDB = legacyDB;
this.batchSize = 100;
}
async migrateProducts() {
const stats = {
total: 0,
migrated: 0,
failed: 0,
errors: []
};
try {
// 1. Get total count
const countResult = await this.legacyDB.query(
'SELECT COUNT(*) as total FROM products'
);
stats.total = countResult[0].total;
console.log(`Migrating ${stats.total} products...`);
// 2. Process in batches
let offset = 0;
while (offset < stats.total) {
const batch = await this.fetchLegacyBatch(offset);
const transformed = this.transformProducts(batch);
try {
await this.coreAPI.post('/api/v4/core/products/batch', {
records: transformed
});
stats.migrated += batch.length;
console.log(`Progress: ${stats.migrated}/${stats.total}`);
} catch (error) {
stats.failed += batch.length;
stats.errors.push({
offset: offset,
count: batch.length,
error: error.message
});
}
offset += this.batchSize;
}
return stats;
} catch (error) {
console.error('Migration failed:', error);
throw error;
}
}
async fetchLegacyBatch(offset) {
return this.legacyDB.query(
`SELECT * FROM products LIMIT ${this.batchSize} OFFSET ${offset}`
);
}
transformProducts(legacyProducts) {
return legacyProducts.map(legacy => ({
XPRD01: legacy.name,
XPRD02: legacy.price,
XPRD03: legacy.code,
XPRD04: this.slugify(legacy.name),
XPRD05: legacy.category_id,
XPRD06: legacy.active ? 'Y' : 'N',
TREC: 'N'
}));
}
slugify(text) {
return text
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '');
}
// Validation
async validateMigration() {
const [legacyCount, coreCount] = await Promise.all([
this.legacyDB.query('SELECT COUNT(*) as total FROM products'),
this.coreAPI.get('/api/v4/core/products', {params: {limit: 0}})
]);
return {
legacy: legacyCount[0].total,
core: coreCount.total,
match: legacyCount[0].total === coreCount.total
};
}
}
// Usage
const migrationService = new DataMigrationService(coreAPIClient, legacyDB);
// Run migration
const stats = await migrationService.migrateProducts();
console.log(`Migrated: ${stats.migrated}/${stats.total}`);
console.log(`Failed: ${stats.failed}`);
// Validate
const validation = await migrationService.validateMigration();
console.log(`Validation: ${validation.match ? 'PASS' : 'FAIL'}`);
Summary
- ✅ Product catalog: Caching, bulk updates, search
- ✅ Order processing: Complete lifecycle management
- ✅ Multi-tenancy: Data isolation per tenant
- ✅ Real-time dashboard: Live metrics with WebSocket
- ✅ Data migration: Batch processing with validation
Key Takeaways:
- Use caching for frequently accessed data
- Implement proper error handling and retry logic
- Leverage batch operations for performance
- Apply context correctly for multi-tenancy
- Subscribe to OUTBOX events for real-time updates
- Transform legacy data carefully during migration
- Validate data after migration
Related Concepts
- API Operations - API reference
- Query Patterns - Advanced queries
- Write Patterns - CRUD operations
- Performance Tips - Optimization
- Best Practices - Overview