Cloud Sync Examples
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
Cloud Sync Examples
Our storage system provides seamless integration with cloud services and REST APIs. This guide shows practical examples of syncing data with Firestore and REST APIs using our @mock-api integration.
🎮 Live Demo Components
- API Sync Demo - Interactive REST API sync testing
- Firestore Sync Demo - Real Firebase sync operations
🔥 Firestore Integration
Setup & Configuration
// app.config.ts
import { provideGgStorage } from '@storage/angular';
import { FirestoreSyncAdapter, FIRESTORE_SYNC_CONFIG } from '@storage/sync';
providers: [
...provideGgStorage({
namespace: 'myapp',
sync: {
adapter: new FirestoreSyncAdapter({
projectId: 'your-firebase-project',
collection: 'storage-sync',
apiKey: 'your-api-key',
authDomain: 'your-project.firebaseapp.com'
})
}
}),
// Or provide configuration separately
{
provide: FIRESTORE_SYNC_CONFIG,
useValue: {
projectId: 'your-firebase-project',
collection: 'storage-sync',
apiKey: 'your-api-key'
}
}
]
Basic Sync Operations
// component.ts
import { inject } from '@angular/core';
import { StorageService } from '@storage/angular';
const storage = inject(StorageService);
// Save locally and sync to Firestore automatically
await storage.put('user/profile', {
name: 'John Doe',
email: '[email protected]',
preferences: { theme: 'dark' }
});
// Data is automatically pushed to Firestore
// Firestore document: /storage-sync/user%2Fprofile
Manual Sync Control
// Get the Firestore adapter for manual operations
const firestoreAdapter = storage.getSyncAdapter() as FirestoreSyncAdapter;
// Push specific changes
const changes = [{
key: 'user/settings',
op: 'put' as const,
value: { notifications: true },
updatedAt: Date.now()
}];
await firestoreAdapter.push(changes);
// Pull remote changes
const status = await firestoreAdapter.getStatus();
const remoteChanges = await firestoreAdapter.pull(status.cursor);
// Apply remote changes locally
for (const change of remoteChanges) {
if (change.op === 'put') {
await storage.put(change.key, change.value);
} else if (change.op === 'remove') {
await storage.remove(change.key);
}
}
Firestore Security Rules
// firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Storage sync collection
match /storage-sync/{document} {
allow read, write: if request.auth != null;
}
// User-specific data
match /storage-sync/{userId}/{document=**} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
🌐 REST API Integration
Setup with Mock API
// app.config.ts
import { provideGgStorage } from '@storage/angular';
import { ApiSyncAdapter, API_SYNC_CONFIG } from '@storage/sync';
providers: [
...provideGgStorage({
namespace: 'myapp',
sync: {
adapter: new ApiSyncAdapter({
baseUrl: 'http://localhost:3000/api',
endpoint: '/storage/sync',
apiKey: 'your-api-key'
})
}
})
]
Mock API Endpoints
// mock-api/storage.mock.ts
import { MockApiHandler } from '@mock-api/core';
export const storageMockApi: MockApiHandler[] = [
// Get sync status and changes
{
method: 'GET',
path: '/api/storage/sync',
handler: (req) => {
const cursor = req.query.cursor || '0';
return {
cursor: Date.now().toString(),
changes: [
{
key: 'user/profile',
op: 'put',
value: { name: 'John', updated: true },
updatedAt: Date.now()
}
]
};
}
},
// Push changes to server
{
method: 'POST',
path: '/api/storage/sync',
handler: (req) => {
const changes = req.body.changes;
console.log('Received changes:', changes);
// Store changes in mock database
changes.forEach(change => {
mockDatabase.set(change.key, change);
});
return {
success: true,
cursor: Date.now().toString(),
processed: changes.length
};
}
},
// Get specific data by key
{
method: 'GET',
path: '/api/storage/data/:key',
handler: (req) => {
const key = decodeURIComponent(req.params.key);
const data = mockDatabase.get(key);
if (!data) {
return { error: 'Not found' };
}
return {
key,
value: data.value,
updatedAt: data.updatedAt
};
}
},
// Update specific data
{
method: 'PUT',
path: '/api/storage/data/:key',
handler: (req) => {
const key = decodeURIComponent(req.params.key);
const { value } = req.body;
mockDatabase.set(key, {
key,
op: 'put',
value,
updatedAt: Date.now()
});
return {
success: true,
key,
updatedAt: Date.now()
};
}
}
];
// Simple in-memory mock database
const mockDatabase = new Map();
API Sync Operations
// component.ts
const storage = inject(StorageService);
const apiAdapter = storage.getSyncAdapter() as ApiSyncAdapter;
// Automatic sync on data changes
await storage.put('user/settings', {
theme: 'dark',
language: 'en',
notifications: true
});
// Automatically synced to: POST /api/storage/sync
// Manual bidirectional sync
async function performSync() {
try {
// Get current sync status
const status = await apiAdapter.getStatus();
console.log('Current cursor:', status.cursor);
// Pull remote changes first
const remoteChanges = await apiAdapter.pull(status.cursor);
console.log('Pulled changes:', remoteChanges);
// Apply remote changes locally
for (const change of remoteChanges) {
if (change.op === 'put') {
await storage.put(change.key, change.value);
} else if (change.op === 'remove') {
await storage.remove(change.key);
}
}
// Push any local changes
const localChanges = await getLocalChanges(); // Your implementation
if (localChanges.length > 0) {
await apiAdapter.push(localChanges);
}
console.log('Sync completed successfully');
} catch (error) {
console.error('Sync failed:', error);
}
}
🔄 Conflict Resolution
Last-Write-Wins Strategy
// Simple conflict resolution
const apiAdapter = new ApiSyncAdapter({
baseUrl: 'http://localhost:3000/api',
endpoint: '/storage/sync',
conflictResolution: 'last-write-wins' // Default
});
Custom Conflict Resolution
// Advanced conflict resolution
const apiAdapter = new ApiSyncAdapter({
baseUrl: 'http://localhost:3000/api',
endpoint: '/storage/sync',
conflictResolution: async (local, remote) => {
// Custom logic for resolving conflicts
if (local.key.startsWith('user/')) {
// User data: prefer local changes
return local;
} else if (remote.updatedAt > local.updatedAt) {
// General data: prefer newer timestamp
return remote;
} else {
return local;
}
}
});
📊 Monitoring & Debugging
Sync Status Monitoring
// Monitor sync status
const adapter = storage.getSyncAdapter();
setInterval(async () => {
const status = await adapter.getStatus();
console.log('Sync Status:', {
cursor: status.cursor,
lastSync: new Date(status.lastSync),
pendingChanges: status.pendingChanges
});
}, 30000); // Check every 30 seconds
Error Handling
// Robust error handling
try {
await storage.put('critical/data', importantData);
} catch (error) {
if (error.code === 'SYNC_FAILED') {
// Handle sync failure
console.warn('Sync failed, data saved locally:', error.message);
// Retry sync later
setTimeout(() => {
storage.retrySync();
}, 60000);
} else {
// Handle other errors
console.error('Storage error:', error);
}
}
🚀 Performance Optimization
Batch Operations
// Efficient batch syncing
const changes = [
{ key: 'user/profile', op: 'put', value: profile, updatedAt: Date.now() },
{ key: 'user/settings', op: 'put', value: settings, updatedAt: Date.now() },
{ key: 'temp/old-data', op: 'remove', updatedAt: Date.now() }
];
await apiAdapter.push(changes); // Single API call
Selective Sync
// Sync only specific data patterns
const apiAdapter = new ApiSyncAdapter({
baseUrl: 'http://localhost:3000/api',
endpoint: '/storage/sync',
syncFilter: (key) => {
// Only sync user data and settings
return key.startsWith('user/') || key.startsWith('settings/');
}
});
🔐 Security Best Practices
API Authentication
// JWT token authentication
const apiAdapter = new ApiSyncAdapter({
baseUrl: 'https://api.myapp.com',
endpoint: '/storage/sync',
headers: {
'Authorization': `Bearer ${getAuthToken()}`,
'Content-Type': 'application/json'
}
});
// Refresh token automatically
apiAdapter.onAuthError = async () => {
const newToken = await refreshAuthToken();
apiAdapter.updateHeaders({
'Authorization': `Bearer ${newToken}`
});
};
Data Encryption
// Client-side encryption before sync
const apiAdapter = new ApiSyncAdapter({
baseUrl: 'https://api.myapp.com',
endpoint: '/storage/sync',
encrypt: (data) => encryptData(data, userKey),
decrypt: (data) => decryptData(data, userKey)
});
🧪 Testing with Mock API
Development Setup
// development.config.ts
import { storageMockApi } from './mock-api/storage.mock';
providers: [
...provideMockApi(storageMockApi), // Enable mock API
...provideGgStorage({
namespace: 'dev',
sync: {
adapter: new ApiSyncAdapter({
baseUrl: 'http://localhost:4200/api', // Mock API URL
endpoint: '/storage/sync'
})
}
})
]
Integration Tests
// storage-sync.spec.ts
describe('Storage Sync', () => {
let storage: StorageService;
let mockApi: MockApiService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
...provideMockApi(storageMockApi),
...provideGgStorage({
namespace: 'test',
sync: { adapter: new ApiSyncAdapter({...}) }
})
]
});
storage = TestBed.inject(StorageService);
mockApi = TestBed.inject(MockApiService);
});
it('should sync data to API', async () => {
// Setup mock response
mockApi.expectPost('/api/storage/sync').respond({
success: true,
processed: 1
});
// Perform operation
await storage.put('test/data', { value: 'test' });
// Verify API was called
mockApi.verify();
});
});
This comprehensive cloud sync integration enables seamless data synchronization across devices and platforms while maintaining the intelligent, performance-focused approach of our storage system.