-
-
Notifications
You must be signed in to change notification settings - Fork 365
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pass TimeoutError
s to beforeError
hooks
#508
Comments
Is there a particular reason why Our use case is to centralize all errors coming from this library and we're expecting that |
The hook was originally designed to let users enrich HTTP response errors. It also does not receive network errors. Just out of curiosity, if it would receive |
Basically the intent is to have a centralized way to handle errors like "Just out of curiosity, if it would receive TimeoutError, what would you do with it in the hook?" |
The hook expects you to return an error though, so even if it supported receiving
|
Lets imagine that Ky supported this. What would happen on error? You handle the error in |
I suppose with the current design, either way, we'll have to |
How about adding a separate Usage import ky from 'ky';
await ky('https://example.com', {
hooks: {
beforeTimeoutError: [
error => {
// Send logs, show toast, or... etc.
return error;
}
]
}
}); My patch diff --git a/distribution/core/Ky.js b/distribution/core/Ky.js
index f827f13cc3a38a75356b2ad15b505441a1d379ad..6827ab8abee88fb95d58207597e53fab6b803023 100644
--- a/distribution/core/Ky.js
+++ b/distribution/core/Ky.js
@@ -15,7 +15,18 @@ export class Ky {
}
// Delay the fetch so that body method shortcuts can set the Accept header
await Promise.resolve();
- let response = await ky._fetch();
+ let response
+ try {
+ response = await ky._fetch();
+ } catch (error) {
+ if (error instanceof TimeoutError) {
+ for (const hook of ky._options.hooks.beforeTimeoutError) {
+ // eslint-disable-next-line no-await-in-loop
+ error = await hook(error);
+ }
+ }
+ throw error;
+ }
for (const hook of ky._options.hooks.afterResponse) {
// eslint-disable-next-line no-await-in-loop
const modifiedResponse = await hook(ky.request, ky._options, ky._decorateResponse(response.clone()));
@@ -114,6 +125,7 @@ export class Ky {
beforeRetry: [],
beforeError: [],
afterResponse: [],
+ beforeTimeoutError: [],
}, options.hooks),
method: normalizeRequestMethod(options.method ?? this._input.method),
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
diff --git a/distribution/types/hooks.d.ts b/distribution/types/hooks.d.ts
index 158198a6515e33f0af159557f38faa5d02d7b783..9ef26124aa717ae8d7136c78a6af5029b0e10c90 100644
--- a/distribution/types/hooks.d.ts
+++ b/distribution/types/hooks.d.ts
@@ -1,5 +1,5 @@
import { stop } from '../core/constants.js';
-import { HTTPError } from '../index.js';
+import { HTTPError, TimeoutError } from '../index.js';
import type { NormalizedOptions } from './options.js';
export type BeforeRequestHook = (request: Request, options: NormalizedOptions) => Request | Response | void | Promise<Request | Response | void>;
export type BeforeRetryState = {
@@ -11,6 +11,7 @@ export type BeforeRetryState = {
export type BeforeRetryHook = (options: BeforeRetryState) => typeof stop | void | Promise<typeof stop | void>;
export type AfterResponseHook = (request: Request, options: NormalizedOptions, response: Response) => Response | void | Promise<Response | void>;
export type BeforeErrorHook = (error: HTTPError) => HTTPError | Promise<HTTPError>;
+export type BeforeTimeoutErrorHook = (error: TimeoutError) => TimeoutError | Promise<TimeoutError>;
export interface Hooks {
/**
This hook enables you to modify the request right before it is sent. Ky will make no further changes to the request after this. The hook function receives normalized input and options as arguments. You could, forf example, modiy `options.headers` here.
@@ -111,4 +112,6 @@ export interface Hooks {
```
*/
beforeError?: BeforeErrorHook[];
+
+ beforeTimeoutError?: BeforeTimeoutErrorHook[];
}
|
What's your argument for making another hook? |
If we do decide to do this, it should be named |
As I see it, there are really two issues at play here.
I think the main problem is I think of |
I just came across this; i wanted to have a "busy" indicator that works across all requests, regardless of what it's doing, it's working when the request succeeds or gets denied, but on a timeout, the indicator would get "stuck". I don't want to edit the error, I just wanted to be informed of it, basically. That's only possible outside of ky, currently. |
I would say it should be possible to simply and automatically start the retry logic. In my tests, retry already triggered when my PC was without networkt before I start the requests; however, if requests already running, ky waits for the response and gets a timeout. While I can restart the request manually (requires external logic, mimic delay, ...) or set timeout to 9999 minutes (can't give an easy early feedback like "response failed, retrying"), I would like to streamline the logic. |
I think whenever Ky encounters an error that we can easily pass to Make a new issue if you want an option for Ky to swallow the error and resolve with |
TimeoutError
TimeoutError
s to beforeError
hooks
We now have a handy entry point to handle any errors in our app. When an error occurs, we'll show a friendly notification letting you know what went wrong. So, if I add a new API endpoint, I won't need to add this part of the functionality explicitly. How I'll manage the error in the try-catch block is the second question. At the moment I have to add this duplicating logic to ALL(!) API calls in every try-catch. |
That would be great if you will add such hook. Could be very useful in some cases like the one above. |
As of now, the
beforeError
hook only handlesHTTPErrors
. A hook for handling errors likeTimeoutError
would be beneficial to avoid having to wrap every request call intry { ... } catch { ... }
blocksThe text was updated successfully, but these errors were encountered: