Request Deduplication
Optimize your API calls by preventing duplicate requests
Request deduplication prevents redundant API calls when multiple requests are made to the same endpoint. For example, if a user rapidly clicks a "Refresh Profile" button - without deduplication, it would trigger multiple API calls for the same data. With deduplication, these duplicate calls are handled based on your strategy.
Key benefits:
- Prevents duplicate API calls
- Reduces network requests
- Prevents race conditions
How it works
Request deduplication works by:
- Generating a unique key for each request based on URL and parameters by default (can be customized via dedupeKey)
- Tracking in-flight requests using this key
- Handling requests with the same key (duplicates) according to your chosen strategy
Requests are only deduplicated when made from the same callApi instance. Requests made from different
instances will be handled independently.
import { } from "@zayne-labs/callapi";
const = ();
const = ();
const = ();
Shared deduplication - these requests are from the same callApi instance, so they will be deduped according to the strategyconst = ("/users");
const = ("/users"); // Will dedupe with resultOne
Independent deduplication - these requests are from different callApi instances, therefore no deduplication occurs between themconst = ("/users"); // Independent deduplication
const = ("/users"); // Independent deduplicationUsage
CallApi provides three deduplication strategies:
1. Cancel Strategy (Default)
- Cancels any existing request when a new identical request is made
- Best for scenarios where you only need the latest data
const { data } = await callMainApi("/users/123", {
dedupeStrategy: "cancel",
});
2. Defer Strategy
The defer strategy shares the same response promise between duplicate requests. If a request is made while an identical one is still in-flight, it will receive the same response.
Example: Multiple components requesting user data simultaneously
import { useState, useEffect } from "react";
function ProfileHeader() {
const [userData, setUserData] = useState(null);
useEffect(() => {
callMainApi("/users/123", {
dedupeStrategy: "defer",
onSuccess: ({ data }) => setUserData(data),
});
}, []);
if (!userData) return null;
return <h1>{userData.name}</h1>;
}
function ProfileDetails() {
const [userData, setUserData] = useState(null);
useEffect(() => {
// This will reuse the in-flight request from ProfileHeader
callMainApi("/users/123", {
dedupeStrategy: "defer",
onSuccess: ({ data }) => setUserData(data),
});
}, []);
if (!userData) return null;
return <div>{userData.email}</div>;
}3. None Strategy
The none strategy disables deduplication, allowing each request to execute independently:
const { data } = await callMainApi("/users/123", {
dedupeStrategy: "none",
});Custom deduplication key
By default, callApi generates a dedupeKey based on the request URL and parameters. You can customize this by providing either a static string or a callback function using the dedupeKey option:
Static deduplication key
const { data } = await callMainApi("/users/123", {
dedupeKey: "custom-key",
});Dynamic deduplication key with callback
For more advanced use cases, you can provide a callback function that receives the request context and returns a custom key:
// URL and method only - ignore headers and body
await callMainApi("/api/user/123", {
dedupeKey: (context) => `${context.options.method}:${context.options.fullURL}`,
});
// Include specific headers in deduplication
await callMainApi("/api/data", {
dedupeKey: (context) => {
const authHeader = context.request.headers.get("Authorization");
return `${context.options.fullURL}-${authHeader}`;
},
});
// User-specific deduplication
await callMainApi("/api/dashboard", {
dedupeKey: (context) => {
const userId = context.options.fullURL.match(/user\/(\d+)/)?.[1];
return `dashboard-${userId}`;
},
});The callback receives a RequestContext object with the following properties:
context.options- Merged options including URL, method, and other configurationcontext.request- The request object with headers, body, etc.context.baseConfig- Base configuration fromcreateFetchClientcontext.config- Instance-specific configuration
Recommendations
- Use
cancelwhen you only need the most recent request (most common) - Use
deferwhen multiple parts of your app need the same data simultaneously - Use
nonewhen requests must be independent (polling, etc.)
Types
Prop
Type
Last updated on 10/21/2025