wretch
wretch copied to clipboard
Retry Middleware
Hey guys 👋🏿 I'm having issues with the retry middleware.
How can I retry a request only when it's a fetchError only and not for all requests?
I tried the retryOnNetworkError as true and false and noticed it sends a retry for non fetchError requests.
import wretch from "wretch"
import fetch from 'node-fetch';
import { retry } from "wretch/middlewares";
global.fetch = fetch;
wretch()
.polyfills({ fetch: global.fetch })
.middlewares([
retry({
maxAttempts: 4, // Maximum number of retry attempts
retryOnNetworkError: true,
resolveWithLatestResponse: true, // Resolve with the latest response
onRetry: ({ error, options, response, url }) => {
if (error) {
console.log(`Retrying attempt ${error.attempt} for ${url}`);
} else {
console.log(`No error object present for ${url}, review if retry is necessary.`);
}
},
skip: (url, opts) => {
console.log(`url: ${url}`);
return false;
}
})
]);
// usage
wretch(API_URI)
.defer((w, url, options) => {
if (options.context?.token) {
return w.auth(`Bearer ${options.context.token}`);
}
return w
})
.resolve(resolver =>
// Validation error
resolver.error(422, err => {
let error = null;
try {
let json = JSON.parse(err.text);
let errMsg = _.flatten(_.map(json.errors, _.values))
error = `${json.message} ${errMsg}`;
} catch (e) {
error = `Sorry, please try again. 422 Unprocessable Entity.`;
}
throwApiError(error);
})
// Unauthenticated
.error(401, err => {
throwApiError('Sorry, please try again. 401 Unauthenticated.');
})
// Unauthorized
.error(403, err => {
throwApiError('Sorry, please try again. 403 Unauthorized.');
})
// Payload Too Large
.error(413, err => {
throwApiError('Sorry, please try again. 413 Payload Too Large.');
})
// Too many requests
.error(429, err => {
throwApiError('Sorry, please try again. 429 Too many requests.');
})
// Client Closed Request
.error(499, err => {
throwApiError('Sorry, please try again. 499 Client Closed Request.');
})
// Server error
.error(500, err => {
throwApiError('Sorry, please try again. 500 Server error.');
})
// Bad Gateway
.error(502, err => {
throwApiError('Sorry, please try again. 502 Bad Gateway.')
})
// Generic fetch error
.fetchError(err => {
console.log('got here');
console.log(err);
throwApiError('Sorry, please try again. Fetch error.');
})
Hey @opheus2,
Did you try using the until option?
You can pass it to the middleware like this:
retry({
// Replace the default condition with a custom one:
until: (response, error) => !error
})
Sadly that doesn't do the trick either @elbywan it keeps sending a request even if it is not failed.
perhaps we can add a flag to make it work only for network errors.
retryOnlyOnNetworkError: true
Sadly that doesn't do the trick either @elbywan it keeps sending a request even if it is not failed.
@opheus2 Hmm weird it seems to be working on my end:
import wretch from "wretch"
import { retry } from "wretch/middlewares";
const api = wretch("https://httpstat.us")
.middlewares([
retry({
maxAttempts: 4, // Maximum number of retry attempts
retryOnNetworkError: true,
resolveWithLatestResponse: true, // Resolve with the latest response
until: (response, error) => !error,
onRetry: ({ error, options, response, url }) => {
if (error) {
console.log(`Retrying because of error "${error.message}" for ${url}`);
} else {
console.log(`No error object present for ${url}, review if retry is necessary.`);
}
},
skip: (url, opts) => {
console.log(`url: ${url}`);
return false;
}
})
])
.resolve(resolver =>
resolver
.badRequest(err => {
console.log('bad request');
console.log(err.message);
})
// Generic fetch error
.fetchError(err => {
console.log('fetch error');
console.log(err.message);
}))
api.get("/400").text(console.log).catch(error => console.log(error.message))
url: https://httpstat.us/400
bad request
400 Bad Request
url: https://httpstatsssssssss.us/400
Retrying because of error "fetch failed" for https://httpstatsssssssss.us/400
Retrying because of error "fetch failed" for https://httpstatsssssssss.us/400
Retrying because of error "fetch failed" for https://httpstatsssssssss.us/400
Retrying because of error "fetch failed" for https://httpstatsssssssss.us/400
fetch error
fetch failed
@opheus2 any news? Did I miss something?
Hi @elbywan
I have now tested this and can confirm yes this approach is working. I my previous test after your first suggestion revolved around my solution using then until: (response, error) => !error, without the respect part of the middleware, hence the weird behaviour. Thank you and I'd close this now