Integration Guide
Table of Contents
- Getting Started
- Authentication Integration
- Data Management Workflows
- Real-time Integration
- File Upload Integration
- Multi-tenant Integration
- Error Handling Patterns
- Frontend Integration Examples
- Mobile App Integration
- Testing Your Integration
Getting Started
This guide provides practical examples and patterns for integrating with the BAASIX API. Each example includes complete code snippets that you can adapt for your application.
Initial Setup
// Base API configuration
const BAASIX_BASE_URL = 'https://your-baasix-instance.com';
const API_VERSION = 'v1'; // Optional if using versioning
// HTTP client setup (using fetch)
class BaaSixClient {
constructor(baseUrl, token = null) {
this.baseUrl = baseUrl;
this.token = token;
}
async request(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
const config = {
...options,
headers: {
'Content-Type': 'application/json',
...(this.token && { 'Authorization': `Bearer ${this.token}` }),
...options.headers,
},
};
try {
const response = await fetch(url, config);
if (!response.ok) {
const error = await response.json().catch(() => ({
message: response.statusText,
code: response.status
}));
throw new BaaSixError(error.message, error.code, error.details);
}
return await response.json();
} catch (error) {
if (error instanceof BaaSixError) throw error;
throw new BaaSixError('Network error', 0, { originalError: error });
}
}
// Convenience methods
get(endpoint) { return this.request(endpoint, { method: 'GET' }); }
post(endpoint, data) { return this.request(endpoint, { method: 'POST', body: JSON.stringify(data) }); }
patch(endpoint, data) { return this.request(endpoint, { method: 'PATCH', body: JSON.stringify(data) }); }
delete(endpoint) { return this.request(endpoint, { method: 'DELETE' }); }
}
// Custom error class
class BaaSixError extends Error {
constructor(message, code, details = {}) {
super(message);
this.name = 'BaaSixError';
this.code = code;
this.details = details;
}
}
// Initialize client
const baasix = new BaaSixClient(BAASIX_BASE_URL);Authentication Integration
Complete Authentication Flow
class AuthManager {
constructor(client) {
this.client = client;
this.token = localStorage.getItem('baasix_token');
this.user = JSON.parse(localStorage.getItem('baasix_user') || 'null');
if (this.token) {
this.client.token = this.token;
}
}
async login(email, password) {
try {
const response = await this.client.post('/auth/login', {
email,
password
});
this.token = response.token;
this.user = response.user;
this.client.token = this.token;
// Persist authentication
localStorage.setItem('baasix_token', this.token);
localStorage.setItem('baasix_user', JSON.stringify(this.user));
return { success: true, user: this.user };
} catch (error) {
console.error('Login failed:', error);
return { success: false, error: error.message };
}
}
async register(userData) {
try {
const response = await this.client.post('/auth/register', userData);
// Auto-login after registration
if (response.token) {
return await this.login(userData.email, userData.password);
}
return { success: true, message: 'Registration successful' };
} catch (error) {
return { success: false, error: error.message };
}
}
async logout() {
try {
await this.client.get('/auth/logout');
} catch (error) {
console.error('Logout request failed:', error);
} finally {
// Clear local state regardless of API response
this.token = null;
this.user = null;
this.client.token = null;
localStorage.removeItem('baasix_token');
localStorage.removeItem('baasix_user');
}
}
async getCurrentUser() {
if (!this.token) return null;
try {
const response = await this.client.get('/auth/me');
this.user = response.data;
localStorage.setItem('baasix_user', JSON.stringify(this.user));
return this.user;
} catch (error) {
// Token might be expired
await this.logout();
return null;
}
}
async refreshToken() {
// If your API supports token refresh
try {
const response = await this.client.post('/auth/refresh');
this.token = response.token;
this.client.token = this.token;
localStorage.setItem('baasix_token', this.token);
return true;
} catch (error) {
await this.logout();
return false;
}
}
isAuthenticated() {
return !!this.token;
}
}
// Usage
const auth = new AuthManager(baasix);
// Login example
const loginForm = document.getElementById('loginForm');
loginForm.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const result = await auth.login(
formData.get('email'),
formData.get('password')
);
if (result.success) {
window.location.href = '/dashboard';
} else {
showError(result.error);
}
});Magic Link Authentication
class MagicLinkAuth {
constructor(client) {
this.client = client;
}
async requestMagicLink(email, redirectUrl = null) {
try {
const response = await this.client.post('/auth/magiclink', {
email,
redirectUrl: redirectUrl || window.location.origin + '/auth/verify'
});
return {
success: true,
message: 'Magic link sent to your email'
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
async verifyMagicLink(token) {
try {
const response = await this.client.get(`/auth/magiclink/${token}`);
// Store the authentication token
localStorage.setItem('baasix_token', response.token);
localStorage.setItem('baasix_user', JSON.stringify(response.user));
return {
success: true,
user: response.user,
token: response.token
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
}
// Usage for magic link
const magicAuth = new MagicLinkAuth(baasix);
// Request magic link
document.getElementById('magicLinkBtn').addEventListener('click', async () => {
const email = document.getElementById('email').value;
const result = await magicAuth.requestMagicLink(email);
if (result.success) {
showMessage('Check your email for the login link');
} else {
showError(result.error);
}
});
// Verify magic link (on the redirect page)
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');
if (token) {
magicAuth.verifyMagicLink(token).then(result => {
if (result.success) {
window.location.href = '/dashboard';
} else {
showError('Invalid or expired link');
}
});
}Data Management Workflows
Complete CRUD Operations
class DataManager {
constructor(client) {
this.client = client;
}
// Create with validation and error handling
async create(collection, data, options = {}) {
try {
// Validate required fields (client-side)
if (options.requiredFields) {
const missing = options.requiredFields.filter(field => !data[field]);
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(', ')}`);
}
}
const response = await this.client.post(`/items/${collection}`, data);
// Handle post-creation actions
if (options.onCreate) {
await options.onCreate(response.data);
}
return {
success: true,
data: response.data,
id: response.data.id
};
} catch (error) {
return {
success: false,
error: error.message,
details: error.details
};
}
}
// Read with complex queries
async read(collection, options = {}) {
try {
const queryParams = new URLSearchParams();
// Build query parameters
if (options.fields) {
queryParams.append('fields', Array.isArray(options.fields)
? options.fields.join(',')
: options.fields
);
}
if (options.filter) {
queryParams.append('filter', JSON.stringify(options.filter));
}
if (options.sort) {
queryParams.append('sort', JSON.stringify(options.sort));
}
if (options.limit) {
queryParams.append('limit', options.limit);
}
if (options.page) {
queryParams.append('page', options.page);
}
if (options.search) {
queryParams.append('search', options.search);
if (options.searchFields) {
queryParams.append('searchFields', options.searchFields.join(','));
}
}
const url = `/items/${collection}?${queryParams.toString()}`;
const response = await this.client.get(url);
return {
success: true,
data: response.data,
totalCount: response.totalCount,
page: options.page || 1,
limit: options.limit || response.data.length
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
// Update with optimistic locking
async update(collection, id, data, options = {}) {
try {
// Optimistic locking check
if (options.version && data.version !== options.version) {
throw new Error('Record has been modified by another user');
}
const response = await this.client.patch(`/items/${collection}/${id}`, data);
if (options.onUpdate) {
await options.onUpdate(response.data);
}
return {
success: true,
data: response.data
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
// Delete with confirmation
async delete(collection, id, options = {}) {
try {
if (options.confirm && !confirm('Are you sure you want to delete this item?')) {
return { success: false, cancelled: true };
}
await this.client.delete(`/items/${collection}/${id}`);
if (options.onDelete) {
await options.onDelete(id);
}
return { success: true };
} catch (error) {
return {
success: false,
error: error.message
};
}
}
// Batch operations
async batchCreate(collection, items) {
const results = [];
for (const item of items) {
const result = await this.create(collection, item);
results.push(result);
// Stop on first error (optional)
if (!result.success) {
return {
success: false,
results,
error: `Batch create failed at item ${results.length}`
};
}
}
return {
success: true,
results,
created: results.length
};
}
}
// Usage examples
const dataManager = new DataManager(baasix);
// Create a blog post
const createPost = async () => {
const result = await dataManager.create('posts', {
title: 'My First Post',
content: 'This is the content of my first post.',
status: 'draft'
}, {
requiredFields: ['title', 'content'],
onCreate: (post) => {
console.log('Post created:', post);
// Redirect to edit page
window.location.href = `/posts/${post.id}/edit`;
}
});
if (!result.success) {
showError(result.error);
}
};
// Read posts with pagination and search
const loadPosts = async (page = 1, search = '') => {
const result = await dataManager.read('posts', {
fields: ['id', 'title', 'excerpt', 'createdAt', 'author.name'],
filter: {
status: 'published'
},
sort: {
createdAt: 'desc'
},
limit: 10,
page,
search,
searchFields: ['title', 'content']
});
if (result.success) {
displayPosts(result.data);
updatePagination(result.page, result.totalCount, result.limit);
} else {
showError(result.error);
}
};Advanced Query Patterns
class AdvancedQueries {
constructor(client) {
this.client = client;
}
// Dashboard analytics query
async getDashboardStats(dateRange = 30) {
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - dateRange);
try {
const [postsStats, usersStats, commentsStats] = await Promise.all([
// Posts analytics
this.client.post('/items/posts', {
filter: {
createdAt: {
gte: startDate.toISOString(),
lte: endDate.toISOString()
}
},
groupBy: ['date:day:createdAt'],
aggregate: {
totalPosts: { function: 'count', field: 'id' },
totalViews: { function: 'sum', field: 'views' }
}
}),
// User registration stats
this.client.post('/items/baasix_User', {
filter: {
createdAt: {
gte: startDate.toISOString(),
lte: endDate.toISOString()
}
},
groupBy: ['date:day:createdAt'],
aggregate: {
newUsers: { function: 'count', field: 'id' }
}
}),
// Comments activity
this.client.post('/items/comments', {
filter: {
createdAt: {
gte: startDate.toISOString(),
lte: endDate.toISOString()
}
},
aggregate: {
totalComments: { function: 'count', field: 'id' },
avgCommentsPerPost: { function: 'avg', field: 'post_id' }
}
})
]);
return {
posts: postsStats.data,
users: usersStats.data,
comments: commentsStats.data
};
} catch (error) {
throw new Error(`Failed to load dashboard stats: ${error.message}`);
}
}
// Complex relational query
async getPostsWithFullData(filters = {}) {
try {
const response = await this.client.post('/items/posts', {
fields: [
'id', 'title', 'excerpt', 'content', 'status', 'createdAt',
'author.name', 'author.email', 'author.profile.avatar',
'category.name', 'category.slug',
'tags.name', 'tags.color',
'comments.content', 'comments.createdAt', 'comments.user.name'
],
filter: {
AND: [
{ status: 'published' },
{ 'author.status': 'active' },
{ 'comments.approved': true },
...Object.entries(filters).map(([key, value]) => ({ [key]: value }))
]
},
sort: {
createdAt: 'desc'
},
limit: 20
});
return response.data.map(post => ({
...post,
// Calculate derived properties
commentCount: post.comments ? post.comments.length : 0,
hasComments: post.comments && post.comments.length > 0,
tagNames: post.tags ? post.tags.map(tag => tag.name) : []
}));
} catch (error) {
throw new Error(`Failed to load posts: ${error.message}`);
}
}
// Geospatial query example
async findNearbyStores(lat, lng, radius = 5000) {
try {
const response = await this.client.post('/items/stores', {
fields: [
'id', 'name', 'address', 'phone',
'$ST_Distance(location, ST_MakePoint(' + lng + ', ' + lat + '))$ as distance'
],
filter: {
AND: [
{ status: 'active' },
{
location: {
dwithin: {
point: [lng, lat],
distance: radius
}
}
}
]
},
sort: {
distance: 'asc'
},
limit: 10
});
return response.data;
} catch (error) {
throw new Error(`Failed to find nearby stores: ${error.message}`);
}
}
}Real-time Integration
Socket.IO Client Integration
See also:
- Socket setup guide: Socket.IO Integration
class RealtimeManager {
constructor(baseUrl, token) {
this.baseUrl = baseUrl;
this.token = token;
this.socket = null;
this.eventHandlers = new Map();
}
async connect() {
// Import socket.io-client (or include via CDN)
const io = await import('socket.io-client');
this.socket = io.connect(this.baseUrl, {
path: '/realtime',
auth: {
token: this.token
},
transports: ['websocket', 'polling']
});
this.setupEventHandlers();
return new Promise((resolve, reject) => {
this.socket.on('connect', () => {
console.log('Connected to BAASIX realtime server');
resolve();
});
this.socket.on('connect_error', (error) => {
console.error('Connection failed:', error);
reject(error);
});
});
}
setupEventHandlers() {
// Handle item events
this.socket.on('item.created', (data) => {
this.handleEvent('item.created', data);
});
this.socket.on('item.updated', (data) => {
this.handleEvent('item.updated', data);
});
this.socket.on('item.deleted', (data) => {
this.handleEvent('item.deleted', data);
});
// Handle notification events
this.socket.on('notification.new', (data) => {
this.handleEvent('notification.new', data);
this.showNotification(data.notification);
});
// Handle user events
this.socket.on('user.connected', (data) => {
this.handleEvent('user.connected', data);
});
this.socket.on('user.disconnected', (data) => {
this.handleEvent('user.disconnected', data);
});
}
handleEvent(eventType, data) {
const handlers = this.eventHandlers.get(eventType) || [];
handlers.forEach(handler => {
try {
handler(data);
} catch (error) {
console.error(`Error in ${eventType} handler:`, error);
}
});
}
on(eventType, handler) {
if (!this.eventHandlers.has(eventType)) {
this.eventHandlers.set(eventType, []);
}
this.eventHandlers.get(eventType).push(handler);
}
off(eventType, handler) {
const handlers = this.eventHandlers.get(eventType);
if (handlers) {
const index = handlers.indexOf(handler);
if (index > -1) {
handlers.splice(index, 1);
}
}
}
showNotification(notification) {
// Create notification UI
const notifElement = document.createElement('div');
notifElement.className = 'notification';
notifElement.innerHTML = `
<h4>${notification.title}</h4>
<p>${notification.message}</p>
<button onclick="this.parentElement.remove()">×</button>
`;
document.getElementById('notifications-container').appendChild(notifElement);
// Auto-remove after 5 seconds
setTimeout(() => {
if (notifElement.parentElement) {
notifElement.remove();
}
}, 5000);
}
disconnect() {
if (this.socket) {
this.socket.disconnect();
this.socket = null;
}
}
}
// Usage
const realtime = new RealtimeManager(BAASIX_BASE_URL, auth.token);
// Connect when user logs in
auth.login(email, password).then(result => {
if (result.success) {
realtime.connect();
}
});
// Listen for specific events
realtime.on('item.created', (data) => {
if (data.collection === 'posts') {
// Refresh posts list
loadPosts();
showMessage(`New post created: ${data.item.title}`);
}
});
realtime.on('notification.new', (data) => {
// Update notification count
updateNotificationBadge();
});
// Live data updates for specific collections
class LiveDataTable {
constructor(collection, container, realtime) {
this.collection = collection;
this.container = container;
this.realtime = realtime;
this.data = [];
this.setupRealtimeListeners();
}
setupRealtimeListeners() {
this.realtime.on('item.created', (data) => {
if (data.collection === this.collection) {
this.data.unshift(data.item);
this.render();
}
});
this.realtime.on('item.updated', (data) => {
if (data.collection === this.collection) {
const index = this.data.findIndex(item => item.id === data.item.id);
if (index > -1) {
this.data[index] = { ...this.data[index], ...data.item };
this.render();
}
}
});
this.realtime.on('item.deleted', (data) => {
if (data.collection === this.collection) {
this.data = this.data.filter(item => item.id !== data.itemId);
this.render();
}
});
}
async load() {
const result = await dataManager.read(this.collection);
if (result.success) {
this.data = result.data;
this.render();
}
}
render() {
// Render table with current data
this.container.innerHTML = `
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Status</th>
<th>Created</th>
</tr>
</thead>
<tbody>
${this.data.map(item => `
<tr>
<td>${item.id}</td>
<td>${item.title}</td>
<td>${item.status}</td>
<td>${new Date(item.createdAt).toLocaleDateString()}</td>
</tr>
`).join('')}
</tbody>
</table>
`;
}
}
// Usage
const postsTable = new LiveDataTable(
'posts',
document.getElementById('posts-table'),
realtime
);
postsTable.load();File Upload Integration
Complete File Upload Solution
class FileManager {
constructor(client) {
this.client = client;
}
async uploadFile(file, options = {}) {
try {
const formData = new FormData();
formData.append('file', file);
if (options.folder) {
formData.append('folder', options.folder);
}
if (options.title) {
formData.append('title', options.title);
}
// Custom upload endpoint that handles FormData
const response = await fetch(`${this.client.baseUrl}/files`, {
method: 'POST',
headers: {
...(this.client.token && { 'Authorization': `Bearer ${this.client.token}` }),
// Don't set Content-Type for FormData
},
body: formData
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Upload failed');
}
const result = await response.json();
if (options.onUpload) {
options.onUpload(result.data);
}
return {
success: true,
file: result.data
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
async uploadWithProgress(file, options = {}) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append('file', file);
// Progress tracking
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable && options.onProgress) {
const percentComplete = (e.loaded / e.total) * 100;
options.onProgress(percentComplete);
}
});
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) {
const response = JSON.parse(xhr.responseText);
resolve({
success: true,
file: response.data
});
} else {
reject(new Error(`Upload failed: ${xhr.statusText}`));
}
});
xhr.addEventListener('error', () => {
reject(new Error('Upload failed'));
});
xhr.open('POST', `${this.client.baseUrl}/files`);
if (this.client.token) {
xhr.setRequestHeader('Authorization', `Bearer ${this.client.token}`);
}
xhr.send(formData);
});
}
async getFileUrl(fileId, options = {}) {
const params = new URLSearchParams();
if (options.width) params.append('width', options.width);
if (options.height) params.append('height', options.height);
if (options.quality) params.append('quality', options.quality);
if (options.format) params.append('format', options.format);
const query = params.toString() ? `?${params.toString()}` : '';
return `${this.client.baseUrl}/assets/${fileId}${query}`;
}
async deleteFile(fileId) {
try {
await this.client.delete(`/files/${fileId}`);
return { success: true };
} catch (error) {
return {
success: false,
error: error.message
};
}
}
}
// File upload component
class FileUploadComponent {
constructor(container, fileManager, options = {}) {
this.container = container;
this.fileManager = fileManager;
this.options = {
multiple: false,
accept: '*/*',
maxSize: 10 * 1024 * 1024, // 10MB
...options
};
this.render();
this.setupEventListeners();
}
render() {
this.container.innerHTML = `
<div class="file-upload">
<input type="file"
id="fileInput"
${this.options.multiple ? 'multiple' : ''}
accept="${this.options.accept}"
style="display: none;">
<div class="upload-area" onclick="document.getElementById('fileInput').click()">
<div class="upload-icon">📁</div>
<div class="upload-text">Click to upload or drag files here</div>
<div class="upload-hint">Max size: ${this.formatFileSize(this.options.maxSize)}</div>
</div>
<div class="upload-progress" style="display: none;">
<div class="progress-bar">
<div class="progress-fill"></div>
</div>
<div class="progress-text">0%</div>
</div>
<div class="uploaded-files"></div>
</div>
`;
}
setupEventListeners() {
const fileInput = this.container.querySelector('#fileInput');
const uploadArea = this.container.querySelector('.upload-area');
fileInput.addEventListener('change', (e) => {
this.handleFiles(Array.from(e.target.files));
});
// Drag and drop
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.classList.add('drag-over');
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.classList.remove('drag-over');
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.classList.remove('drag-over');
this.handleFiles(Array.from(e.dataTransfer.files));
});
}
async handleFiles(files) {
const validFiles = files.filter(file => this.validateFile(file));
if (validFiles.length === 0) {
this.showError('No valid files selected');
return;
}
for (const file of validFiles) {
await this.uploadFile(file);
}
}
validateFile(file) {
if (file.size > this.options.maxSize) {
this.showError(`File ${file.name} is too large`);
return false;
}
if (this.options.accept !== '*/*') {
const acceptedTypes = this.options.accept.split(',').map(t => t.trim());
const fileType = file.type || '';
const fileExtension = '.' + file.name.split('.').pop();
const isAccepted = acceptedTypes.some(type =>
fileType.match(type.replace('*', '.*')) || type === fileExtension
);
if (!isAccepted) {
this.showError(`File type ${fileExtension} not allowed`);
return false;
}
}
return true;
}
async uploadFile(file) {
const progressBar = this.container.querySelector('.progress-fill');
const progressText = this.container.querySelector('.progress-text');
const progressContainer = this.container.querySelector('.upload-progress');
progressContainer.style.display = 'block';
try {
const result = await this.fileManager.uploadWithProgress(file, {
onProgress: (percent) => {
progressBar.style.width = `${percent}%`;
progressText.textContent = `${Math.round(percent)}%`;
},
folder: this.options.folder
});
if (result.success) {
this.displayUploadedFile(result.file);
if (this.options.onFileUploaded) {
this.options.onFileUploaded(result.file);
}
} else {
this.showError(result.error);
}
} catch (error) {
this.showError(error.message);
} finally {
progressContainer.style.display = 'none';
progressBar.style.width = '0%';
progressText.textContent = '0%';
}
}
displayUploadedFile(file) {
const container = this.container.querySelector('.uploaded-files');
const fileElement = document.createElement('div');
fileElement.className = 'uploaded-file';
fileElement.innerHTML = `
<div class="file-info">
<div class="file-name">${file.filename}</div>
<div class="file-size">${this.formatFileSize(file.size)}</div>
</div>
<div class="file-actions">
<button onclick="window.open('${this.fileManager.getFileUrl(file.id)}')">View</button>
<button onclick="this.parentElement.parentElement.remove()">Remove</button>
</div>
`;
container.appendChild(fileElement);
}
formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
showError(message) {
// Show error message to user
console.error(message);
alert(message); // Replace with proper error display
}
}
// Usage
const fileManager = new FileManager(baasix);
// Create file upload component
const uploadComponent = new FileUploadComponent(
document.getElementById('file-upload'),
fileManager,
{
multiple: true,
accept: 'image/*,.pdf,.doc,.docx',
maxSize: 5 * 1024 * 1024, // 5MB
folder: 'uploads',
onFileUploaded: (file) => {
console.log('File uploaded:', file);
// Add to form data or update UI
}
}
);Testing Your Integration
Integration Test Suite
class BaaSixTestSuite {
constructor(client) {
this.client = client;
this.testResults = [];
}
async runAllTests() {
console.log('Starting BAASIX integration tests...');
try {
await this.testAuthentication();
await this.testCRUDOperations();
await this.testAdvancedQueries();
await this.testFileOperations();
await this.testRealtime();
} catch (error) {
console.error('Test suite failed:', error);
}
this.printResults();
}
async testAuthentication() {
const auth = new AuthManager(this.client);
// Test login
await this.test('User Login', async () => {
const result = await auth.login('test@example.com', 'password');
if (!result.success) throw new Error(result.error);
return result.user;
});
// Test current user
await this.test('Get Current User', async () => {
const user = await auth.getCurrentUser();
if (!user) throw new Error('No current user');
return user;
});
}
async testCRUDOperations() {
const dataManager = new DataManager(this.client);
let createdId;
// Test create
await this.test('Create Item', async () => {
const result = await dataManager.create('posts', {
title: 'Test Post',
content: 'This is a test post'
});
if (!result.success) throw new Error(result.error);
createdId = result.id;
return result.data;
});
// Test read
await this.test('Read Items', async () => {
const result = await dataManager.read('posts', {
limit: 10
});
if (!result.success) throw new Error(result.error);
return result.data;
});
// Test update
await this.test('Update Item', async () => {
const result = await dataManager.update('posts', createdId, {
title: 'Updated Test Post'
});
if (!result.success) throw new Error(result.error);
return result.data;
});
// Test delete
await this.test('Delete Item', async () => {
const result = await dataManager.delete('posts', createdId);
if (!result.success) throw new Error(result.error);
return true;
});
}
async test(name, testFunction) {
console.log(`Testing: ${name}`);
try {
const startTime = Date.now();
const result = await testFunction();
const duration = Date.now() - startTime;
this.testResults.push({
name,
status: 'PASS',
duration,
result
});
console.log(`✅ ${name} - ${duration}ms`);
} catch (error) {
this.testResults.push({
name,
status: 'FAIL',
error: error.message
});
console.log(`❌ ${name} - ${error.message}`);
}
}
printResults() {
const passed = this.testResults.filter(r => r.status === 'PASS').length;
const failed = this.testResults.filter(r => r.status === 'FAIL').length;
console.log('\n=== Test Results ===');
console.log(`Total: ${this.testResults.length}`);
console.log(`Passed: ${passed}`);
console.log(`Failed: ${failed}`);
if (failed > 0) {
console.log('\nFailed Tests:');
this.testResults
.filter(r => r.status === 'FAIL')
.forEach(r => console.log(`- ${r.name}: ${r.error}`));
}
}
}
// Run integration tests
const testSuite = new BaaSixTestSuite(baasix);
testSuite.runAllTests();This comprehensive integration guide provides practical, production-ready code examples that demonstrate how to properly integrate with the BAASIX API. Each section includes error handling, best practices, and real-world usage patterns that AI developers can directly adapt and use in their applications.
Related Documentation
- Authentication Routes - API authentication details
- Item Routes - Data CRUD operations
- File Routes - File management APIs
- Socket.IO Integration - Real-time features
- Advanced Query Guide - Complex query patterns