Synchronize Offline Mutations Using Axios
Synchronizing offline mutations with Axios requires a resilient architecture based on request interception, persistent queuing, and sequential execution upon reconnection. This article outlines the optimal strategy for capturing write operations (POST, PUT, PATCH, DELETE) when a user is offline, persisting them locally, and reliably replaying them using Axios interceptors and background sync mechanisms while preventing race conditions and data conflicts.
1. Intercepting and Storing Mutations
The foundation of offline synchronization is identifying when a network mutation fails due to connectivity loss. Axios response interceptors provide the most effective hook for this purpose.
- Detect Network Failures: In the Axios response
interceptor, check for network errors (typically
!error.responseorerror.code === 'ERR_NETWORK') on non-GET requests. - Normalize the Request Payload: Extract the
necessary metadata from
error.config: the HTTP method, URL, headers, and request body (data). - Persist to Storage: Store the serialized request in
a persistent local database, such as IndexedDB (via libraries like
idborDexie.js) orlocalStoragefor smaller datasets. Avoid keeping the queue purely in memory to prevent data loss on page refresh or browser restart.
axios.interceptors.response.use(
(response) => response,
async (error) => {
const { config } = error;
const isMutation = config && ['post', 'put', 'patch', 'delete'].includes(config.method.toLowerCase());
if (!error.response && isMutation) {
await addToOfflineQueue({
id: crypto.randomUUID(),
url: config.url,
method: config.method,
data: config.data,
headers: config.headers,
timestamp: Date.now()
});
return Promise.reject(new Error('Offline: Mutation queued for sync.'));
}
return Promise.reject(error);
}
);2. Network State Monitoring and Synchronization Triggers
Replay should only be initiated when the application regains a stable internet connection.
- Listen for Online Events: Attach listeners to
window.addEventListener('online', processQueue). - Health Check Verification: Browser
onlineevents can produce false positives on captive portals or degraded connections. Ping a lightweight endpoint (/healthor/ping) via Axios to verify actual connectivity before processing the queue. - Background Sync API: For progressive web apps
(PWAs), register a sync event using the Service Worker
SyncManagerto process requests even if the user closes the tab.
3. Sequential Queue Processing (FIFO)
Mutations are often interdependent (for example, creating a resource and subsequently updating it). Executing offline requests in parallel can lead to race conditions and 404/409 errors.
- First-In, First-Out (FIFO) Order: Sort queued
requests by their creation timestamp and process them sequentially using
async/awaitin a loop. - Halt on Dependency Failure: If a mutation fails with a 4xx client error (other than 408/429), pause or discard dependent tasks to avoid cascading failures.
- Atomic Deletion: Remove the mutation from persistent storage only after receiving a successful (2xx) HTTP response from the server.
async function processQueue() {
const queue = await getOfflineQueue(); // Sorted by timestamp ASC
for (const item of queue) {
try {
await axios({
url: item.url,
method: item.method,
data: item.data,
headers: {
...item.headers,
'X-Idempotency-Key': item.id // Prevent duplicate execution
}
});
await removeFromOfflineQueue(item.id);
} catch (error) {
if (error.response && error.response.status >= 400 && error.response.status < 500) {
// Handle unrecoverable client errors (e.g., validation failed)
await logSyncError(item, error);
await removeFromOfflineQueue(item.id);
} else {
// Network failure or server error: stop processing to retry later
break;
}
}
}
}4. Idempotency and Conflict Resolution
Network transitions often cause requests to reach the server without the client receiving the confirmation.
- Idempotency Keys: Attach a unique UUID
(
X-Idempotency-Key) to every queued mutation. The backend must check this key to avoid processing the same action twice (such as duplicate payments or duplicate record creation). - Optimistic UI Rollbacks: When queuing a mutation, update the local UI optimistically. If a queued request fails permanently upon synchronization, trigger a state rollback or alert the user to resolve conflicts manually.