Real-time Updates Guide
The Tracker GraphQL API provides real-time updates through Socket.IO, enabling live tracking and instant notifications.
Getting Started
Socket.IO Client Setup
import { io } from "socket.io-client";
const socket = io("https://your-api-url", {
auth: {
token: "your.jwt.token", // JWT token required
},
transports: ["websocket"],
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
});
Connection Handling
socket.on("connect", () => {
console.log("Connected with ID:", socket.id);
});
socket.on("connect_error", (error) => {
console.error("Connection error:", error.message);
});
socket.on("disconnect", (reason) => {
console.log("Disconnected:", reason);
});
Subscribing to Updates
Location Updates
// Subscribe to tracker updates
socket.emit(
"subscribe",
{
type: "location_updates",
filters: {
tracker_ids: ["tracker_1", "tracker_2"],
},
},
(response) => {
if (response.status === "subscribed") {
console.log("Successfully subscribed to location updates");
}
},
);
// Handle location updates
socket.on("location_update", (data) => {
console.log("New location:", data);
// {
// tracker_id: "tracker_1",
// latitude: 37.7749,
// longitude: -122.4194,
// timestamp: 1635789600,
// speed: 30,
// heading: 180
// }
});
Status Changes
// Subscribe to status changes
socket.emit("subscribe", {
type: "status_updates",
filters: {
status_types: ["online", "offline", "error"],
},
});
// Handle status updates
socket.on("status_change", (data) => {
console.log("Status changed:", data);
// {
// tracker_id: "tracker_1",
// status: "offline",
// timestamp: 1635789600,
// reason: "connection_lost"
// }
});
Event Types
Available Events
interface EventTypes {
// Location Events
location_update: LocationUpdate;
geocoding_complete: GeocodingResult;
// Status Events
status_change: StatusChange;
battery_low: BatteryStatus;
// Alert Events
geofence_breach: GeofenceAlert;
speed_limit: SpeedAlert;
// System Events
maintenance: MaintenanceNotice;
error: ErrorNotification;
}
Event Schemas
interface LocationUpdate {
tracker_id: string;
latitude: number;
longitude: number;
timestamp: number;
speed?: number;
heading?: number;
accuracy?: number;
}
interface StatusChange {
tracker_id: string;
status: "online" | "offline" | "error";
timestamp: number;
reason?: string;
details?: Record<string, any>;
}
Advanced Usage
Batch Subscriptions
// Subscribe to multiple event types
socket.emit(
"subscribe_batch",
{
subscriptions: [
{
type: "location_updates",
filters: { tracker_ids: ["tracker_1"] },
},
{
type: "status_updates",
filters: { status_types: ["error"] },
},
],
},
(response) => {
console.log("Batch subscription result:", response);
},
);
Custom Event Filters
// Subscribe with complex filters
socket.emit("subscribe", {
type: "location_updates",
filters: {
tracker_ids: ["tracker_1"],
min_speed: 30,
regions: ["US-CA", "US-NY"],
update_interval: 60, // seconds
},
});
Error Handling
Reconnection Strategy
const socket = io("https://your-api-url", {
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
randomizationFactor: 0.5,
});
socket.io.on("reconnect_attempt", (attempt) => {
console.log(`Reconnection attempt ${attempt}`);
});
socket.io.on("reconnect_failed", () => {
console.error("Failed to reconnect after all attempts");
});
Event Error Handling
socket.on("error", (error) => {
switch (error.code) {
case "AUTHENTICATION_FAILED":
// Handle authentication errors
refreshToken().then((newToken) => {
socket.auth.token = newToken;
socket.connect();
});
break;
case "SUBSCRIPTION_FAILED":
// Handle subscription errors
console.error("Failed to subscribe:", error.message);
break;
default:
console.error("Socket error:", error);
}
});
Best Practices
1. Connection Management
class SocketManager {
constructor(url, options) {
this.socket = io(url, options);
this.setupListeners();
this.subscriptions = new Map();
}
setupListeners() {
this.socket.on("connect", this.handleConnect.bind(this));
this.socket.on("disconnect", this.handleDisconnect.bind(this));
this.socket.on("error", this.handleError.bind(this));
}
async handleConnect() {
// Resubscribe to previous subscriptions
for (const [type, filters] of this.subscriptions) {
await this.subscribe(type, filters);
}
}
}
2. Event Buffering
class EventBuffer {
constructor(flushInterval = 1000) {
this.buffer = [];
this.flushInterval = flushInterval;
}
add(event) {
this.buffer.push(event);
this.scheduleFlush();
}
async flush() {
if (this.buffer.length === 0) return;
const events = [...this.buffer];
this.buffer = [];
await this.processEvents(events);
}
}
3. Performance Optimization
// Implement throttling for high-frequency events
function throttleEvents(socket, eventName, delay) {
let lastEvent = null;
let timeoutId = null;
socket.on(eventName, (data) => {
lastEvent = data;
if (!timeoutId) {
timeoutId = setTimeout(() => {
if (lastEvent) {
handleEvent(lastEvent);
lastEvent = null;
}
timeoutId = null;
}, delay);
}
});
}
Monitoring
Client-side Metrics
const metrics = {
messageCount: 0,
reconnections: 0,
errors: 0,
latency: [],
track(event) {
this.messageCount++;
this.latency.push(Date.now() - event.timestamp);
// Report metrics every minute
if (this.messageCount % 100 === 0) {
this.reportMetrics();
}
},
};
Health Checks
function checkConnectionHealth() {
return {
connected: socket.connected,
lastMessageTime: lastMessageTime,
reconnectionAttempts: socket.io.reconnectionAttempts,
bufferedMessages: socket.io.engine.writeBuffer.length,
};
}
Security Considerations
- Always use secure WebSocket connections (WSS)
- Implement proper authentication
- Validate all incoming data
- Use rate limiting
- Monitor for suspicious activity