Request deduplication
Use case
Prevent duplicate concurrent requests to the same endpoint. If a request is already in flight, return the same promise instead of making a new network call.
Interceptor recipe
import { createClient } from '@parcely/core'
import type { HttpResponse } from '@parcely/core'
const http = createClient({ baseURL: 'https://api.example.com' })
const inFlight = new Map<string, Promise<HttpResponse<unknown>>>()
http.interceptors.request.use((config) => {
const key = `${config.method ?? 'GET'}:${config.url}`
const existing = inFlight.get(key)
if (existing) {
// Abort this request; caller will get the in-flight promise
const controller = new AbortController()
controller.abort()
return { ...config, signal: controller.signal }
}
return config
})
A simpler approach is to deduplicate at the service layer:
const inFlight = new Map<string, Promise<unknown>>()
async function deduped<T>(key: string, fn: () => Promise<T>): Promise<T> {
const existing = inFlight.get(key)
if (existing) return existing as Promise<T>
const promise = fn().finally(() => inFlight.delete(key))
inFlight.set(key, promise)
return promise
}
// Usage:
const user = await deduped('user:me', () =>
http.get('/users/me').then((r) => r.data),
)
Notes
- Deduplication is most useful for GET requests. Avoid deduplicating POST/PUT/DELETE.
- The in-flight map uses string keys. Customise the key generation for requests with different params.
- Clean up the map entry in
.finally()to prevent memory leaks.