diff --git a/README.md b/README.md index 86dedd4..df02e81 100644 --- a/README.md +++ b/README.md @@ -220,7 +220,7 @@ that is likely more specific. The `TypicalHttpError` includes the `Response` object so consumers can extract more information from it as needed. The default error handing will not have called the `.text()` and `.json()`methods on the response, so these can bue used -when parsing the error. +when parsing the error. Error mappers are allowed to be asynchronous. ```typescript const fetcher = buildCall() // diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 11b02df..b627963 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -1163,6 +1163,54 @@ describe('call builder', () => { expect(scope.isDone()).toEqual(true); }); + it('async error mapper', async () => { + const scope = nock(baseUrl) // + .get('/boop') + .reply(500); + + const fetcher = buildCall() + .path('/boop') + .method('get') + .mapError(async (_err) => { + await new Promise((res) => setTimeout(res, 1)); + return 'async arrar!'; + }) + .build(); + + const res = await fetcher({ baseUrl }); + + expect(res.success).toEqual(false); + expect(res?.error).toEqual('async arrar!'); + expect(res?.error).toMatchInlineSnapshot(`"async arrar!"`); + expect(scope.isDone()).toEqual(true); + }); + + it('mixed sync and async error mapper', async () => { + const scope = nock(baseUrl) // + .get('/boop') + .reply(500); + + const fetcher = buildCall() + .path('/boop') + .method('get') + .mapError((_) => 'error!') + .mapError(async (err) => { + console.log(err); + await new Promise((res) => setTimeout(res, 1)); + return err.toUpperCase(); + }) + + .mapError((err) => `${err}!!11`) + .build(); + + const res = await fetcher({ baseUrl }); + + expect(res.success).toEqual(false); + expect(res?.error).toEqual('ERROR!!!11'); + expect(res?.error).toMatchInlineSnapshot(`"ERROR!!!11"`); + expect(scope.isDone()).toEqual(true); + }); + it.todo('runtype failure'); }); }); diff --git a/src/common.ts b/src/common.ts index 6822015..3934cc9 100644 --- a/src/common.ts +++ b/src/common.ts @@ -84,14 +84,14 @@ export function getFetchParams( return { url, headers, body }; } -export function applyErrorMappers( +export async function applyErrorMappers( error: any, mappers: CallRecord['errorMappers'], args: any, ) { let newError = error; for (const mapper of mappers) { - newError = mapper(newError, args); + newError = await mapper(newError, args); } return newError; } diff --git a/src/index.ts b/src/index.ts index a1389e6..88edc83 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,7 +19,7 @@ export { unwrapError } from './common'; export class CallBuilder< Ret = void, Arg extends Record = { baseUrl: string | URL }, - Err = TypicalWrappedError | TypicalHttpError, + Err = TypicalWrappedError | TypicalHttpError > { private record: CallRecord; @@ -145,7 +145,9 @@ export class CallBuilder< * called multiple times. Each map function will receive the result of the * previous mapper. */ - mapError(mapper: (error: Err, args: Arg) => T): CallBuilder { + mapError( + mapper: (error: Err, args: Arg) => T | Promise, + ): CallBuilder { return new CallBuilder({ ...this.record, errorMappers: [...this.record.errorMappers, mapper], @@ -273,7 +275,7 @@ export class CallBuilder< return { success: false, body: undefined, - error: applyErrorMappers( + error: await applyErrorMappers( new TypicalHttpError(res), errorMappers, args, @@ -307,7 +309,7 @@ export class CallBuilder< return { success: false, body: undefined, - error: applyErrorMappers( + error: await applyErrorMappers( new TypicalWrappedError(error, res, text), errorMappers, args,