Skip to content

Commit

Permalink
🏭 Add fallback catcher method
Browse files Browse the repository at this point in the history
should resolve #192
  • Loading branch information
elbywan committed Jun 28, 2023
1 parent 238d17a commit 46610cf
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 9 deletions.
3 changes: 2 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const JSON_MIME = "application/json"
export const CONTENT_TYPE_HEADER = "Content-Type"
export const FETCH_ERROR = Symbol()
export const FETCH_ERROR = Symbol()
export const CATCHER_FALLBACK = Symbol()
5 changes: 4 additions & 1 deletion src/core.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { mix, extractContentType, isLikelyJsonMime } from "./utils.js"
import { JSON_MIME, CONTENT_TYPE_HEADER } from "./constants.js"
import { JSON_MIME, CONTENT_TYPE_HEADER, CATCHER_FALLBACK } from "./constants.js"
import { resolver } from "./resolver.js"
import config from "./config.js"
import type { Wretch } from "./types.js"
Expand Down Expand Up @@ -65,6 +65,9 @@ export const core: Wretch = {
newMap.set(errorId, catcher)
return { ...this, _catchers: newMap }
},
catcherFallback(catcher) {
return this.catcher(CATCHER_FALLBACK, catcher)
},
resolve<R = unknown>(resolver, clear: boolean = false) {
return { ...this, _resolvers: clear ? [resolver] : [...this._resolvers, resolver] }
},
Expand Down
17 changes: 11 additions & 6 deletions src/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { middlewareHelper } from "./middleware.js"
import { mix } from "./utils.js"
import type { Wretch, WretchResponse, WretchResponseChain, WretchError as WretchErrorType } from "./types.js"
import { FETCH_ERROR } from "./constants.js"
import { FETCH_ERROR, CATCHER_FALLBACK } from "./constants.js"

/**
* This class inheriting from Error is thrown when the fetch response is not "ok".
Expand Down Expand Up @@ -47,7 +47,7 @@ export const resolver = <T, Chain, R>(wretch: T & Wretch<T, Chain, R>) => {
const referenceError = new Error()
const throwingPromise: Promise<void | WretchResponse> = _fetchReq
.catch(error => {
throw { __wrap: error }
throw { [FETCH_ERROR]: error }
})
.then(response => {
if (!response.ok) {
Expand Down Expand Up @@ -75,17 +75,22 @@ export const resolver = <T, Chain, R>(wretch: T & Wretch<T, Chain, R>) => {
// Wraps the Promise in order to dispatch the error to a matching catcher
const catchersWrapper = <T>(promise: Promise<T>): Promise<void | T> => {
return promise.catch(err => {
const error = err.__wrap || err
const fetchErrorFlag = err.hasOwnProperty(FETCH_ERROR)
const error = fetchErrorFlag ? err[FETCH_ERROR] : err

const catcher =
(error.status && catchers.get(error.status)) ||
catchers.get(error.name) || (
err.__wrap && catchers.has(FETCH_ERROR) && catchers.get(FETCH_ERROR)
(error?.status && catchers.get(error.status)) ||
catchers.get(error?.name) || (
fetchErrorFlag && catchers.has(FETCH_ERROR) && catchers.get(FETCH_ERROR)
)

if (catcher)
return catcher(error, wretch)

const catcherFallback = catchers.get(CATCHER_FALLBACK)
if (catcherFallback)
return catcherFallback(error, wretch)

throw error
})
}
Expand Down
22 changes: 21 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,27 @@ export interface Wretch<Self = unknown, Chain = unknown, Resolver = undefined> {
* @param errorId - Error code or name
* @param catcher - The catcher method
*/
catcher(this: Self & Wretch<Self, Chain, Resolver>, errorId: number | string, catcher: (error: WretchError, originalRequest: this) => any): this
catcher(this: Self & Wretch<Self, Chain, Resolver>, errorId: number | string | symbol, catcher: (error: WretchError, originalRequest: this) => any): this

/**
* A fallback catcher that will be called for any error thrown - if uncaught by other means.
*
* ```js
* wretch(url)
* .catcher(404, err => redirect("/routes/notfound", err.message))
* .catcher(500, err => flashMessage("internal.server.error"))
* // this fallback will trigger for any error except the ones caught above (404 and 505)
* .catcherFallback(err => {
* log("Uncaught error:", err)
* throw err
* })
* ```
*
* @category Helpers
* @see {@link Wretch.catcher} for more details.
* @param catcher - The catcher method
*/
catcherFallback(this: Self & Wretch<Self, Chain, Resolver>, catcher: (error: WretchError, originalRequest: this) => any): this

/**
* Defer one or multiple request chain methods that will get called just before the request is sent.
Expand Down
25 changes: 25 additions & 0 deletions test/node/wretch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,31 @@ describe("Wretch", function () {
expect(check).toBe(7)
})

it("should use the fallback catcher", async function () {
let _404 = 0
let fetchError = 0
let fallback = 0

const w = wretch(_URL)
.polyfills({
fetch: fetchPolyfill()
})
.catcher(404, _ => _404++)
.catcherFallback(_ => fallback++)

await w.url("/404").get().res(_ => fallback--)
await w
.polyfills({ fetch: () => Promise.reject() })
.get()
.fetchError(_ => fetchError++)
.res(_ => fallback--)
await w.url("/401").get().res(_ => fallback--)

expect(_404).toBe(1)
expect(fetchError).toBe(1)
expect(fallback).toBe(1)
})

it("should capture the original request with resolvers/catchers", async function () {
let check = 0
const redirectedNotFound = await wretch(`${_URL}/404`)
Expand Down

0 comments on commit 46610cf

Please sign in to comment.