Duplicate POST requests observed when enabling retries on $fetch in Nuxt 3
0 reputation · 25 Mar 2024, 01:24 UTC
0 reputation · 25 Mar 2024, 01:24 UTC
Goal: Use the $fetch composable with a retry option to recover from transient network errors while guaranteeing that mutating HTTP requests (POST, PUT, PATCH) are not retried unless the backend endpoint is explicitly idempotent.
Constraint: Nuxt 3’s default retry mechanism applies only to GET, HEAD, and OPTIONS; setting retry to a number or true enables retries for all methods, and the supplied retry predicate receives only the error and response objects, not the original request method or URL. Developers must therefore manually inspect the method (e.g., via request options stored elsewhere) to block retries on unsafe calls, otherwise duplicate writes can occur.
Uncertainty: It is unclear whether a built‑in “safe‑retry” mode that automatically disables retries for non‑idempotent methods exists or is planned, and how to implement a reliable, low‑boilerplate guard that works globally across all $fetch invocations.
Is there a configuration or plugin that automatically disables retries for POST/PUT/PATCH unless explicitly opted‑in? How can a retry predicate safely determine the request method without accessing the original options? Does Nuxt provide a runtime hook or middleware to enforce safe‑retry behavior globally for all $fetch calls?
Nuxt 3 does not provide a built-in "safe-retry" configuration that allows you to enable retries globally while automatically excluding non-idempotent methods like POST, PUT, and PATCH. When you explicitly set the retry option to a number or true, you override the default ofetch behavior, which normally restricts retries to GET, HEAD, and OPTIONS.
The retry predicate function in $fetch receives only the error and response objects. It does not have access to the original request options (such as the HTTP method). Consequently, you cannot determine if a request is a POST call inside the predicate itself to block the retry.
To enforce safe-retry behavior globally without duplicating boilerplate, create a custom wrapper or a Nuxt plugin that manages the retry logic based on the request method. The most reliable approach is to conditionally apply the retry option only when the method is idempotent.
// composables/useApi.ts
export const useApi = (options = {}) => {
return $fetch({
...options,
// Only enable retries for idempotent methods
retry: ['GET', 'HEAD', 'OPTIONS'].includes(options.method?.toUpperCase())
? 3
: 0,
...options // Ensure specific call overrides take precedence
});
};
If you have specific POST endpoints that are idempotent (e.g., using idempotency keys), you can extend the wrapper to check for a custom flag in the options:
// Example usage
await useApi({
method: 'POST',
body: { id: 'unique-req-123' },
isIdempotent: true, // Custom flag
retry: 3
});
GET requests retry while POST requests fail immediately..toUpperCase() when checking the method, as $fetch may receive methods in varying cases.Diagnostic Detail Needed: Are you using a global $fetch interceptor via a Nuxt plugin, or are you calling $fetch independently across various components?
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.