From ffe404bde43b87d1405b2b78e01b33d46b31aab1 Mon Sep 17 00:00:00 2001 From: Tom Meagher Date: Sat, 30 Mar 2024 12:49:28 -0400 Subject: [PATCH 1/5] feat(http): add onFetchRequest --- site/pages/docs/clients/transports/http.md | 16 ++++++++++++ src/clients/transports/http.test.ts | 21 ++++++++++++++++ src/clients/transports/http.ts | 8 +++--- src/utils/rpc/http.ts | 29 +++++++++++++--------- 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/site/pages/docs/clients/transports/http.md b/site/pages/docs/clients/transports/http.md index 92e5b95150..32ccf84c53 100644 --- a/site/pages/docs/clients/transports/http.md +++ b/site/pages/docs/clients/transports/http.md @@ -171,6 +171,22 @@ const transport = http('https://eth-mainnet.g.alchemy.com/v2/...', { }) ``` +### onFetchRequest (optional) + +- **Type:** `(request: Request) => void` + +A callback to handle the fetch request. Useful for logging or debugging. + +```ts twoslash +import { http } from 'viem' +// ---cut--- +const transport = http('https://eth-mainnet.g.alchemy.com/v2/...', { + onFetchRequest(request) { + console.log(request) // [!code focus] + } +}) +``` + ### onFetchResponse (optional) - **Type:** `(response: Response) => void` diff --git a/src/clients/transports/http.test.ts b/src/clients/transports/http.test.ts index a4bf596515..9a6fec62c9 100644 --- a/src/clients/transports/http.test.ts +++ b/src/clients/transports/http.test.ts @@ -271,6 +271,27 @@ describe('request', () => { await server.close() }) + test.only('behavior: onFetchRequest', async () => { + const server = await createHttpServer((_, res) => { + res.end(JSON.stringify({ result: '0x1' })) + }) + + const requests: Request[] = [] + const transport = http(server.url, { + key: 'mock', + onFetchRequest(request) { + requests.push(request) + }, + })({ chain: localhost }) + + await transport.request({ method: 'eth_blockNumber' }) + + console.log(requests) + expect(requests.length).toBe(1) + + await server.close() + }) + test('behavior: onFetchResponse', async () => { const server = await createHttpServer((_, res) => { res.end(JSON.stringify({ result: '0x1' })) diff --git a/src/clients/transports/http.ts b/src/clients/transports/http.ts index 3f21b478f1..061799e454 100644 --- a/src/clients/transports/http.ts +++ b/src/clients/transports/http.ts @@ -36,9 +36,9 @@ export type HttpTransportConfig = { * @link https://developer.mozilla.org/en-US/docs/Web/API/fetch */ fetchOptions?: HttpRpcClientOptions['fetchOptions'] | undefined - /** - * A callback to handle the response from `fetch`. - */ + /** A callback to handle the response from `fetch`. */ + onFetchRequest?: HttpRpcClientOptions['onRequest'] | undefined + /** A callback to handle the response from `fetch`. */ onFetchResponse?: HttpRpcClientOptions['onResponse'] | undefined /** The key of the HTTP transport. */ key?: TransportConfig['key'] | undefined @@ -78,6 +78,7 @@ export function http( fetchOptions, key = 'http', name = 'HTTP JSON-RPC', + onFetchRequest, onFetchResponse, retryDelay, } = config @@ -91,6 +92,7 @@ export function http( const rpcClient = getHttpRpcClient(url_, { fetchOptions, + onRequest: onFetchRequest, onResponse: onFetchResponse, timeout, }) diff --git a/src/utils/rpc/http.ts b/src/utils/rpc/http.ts index 76d4125538..8131716712 100644 --- a/src/utils/rpc/http.ts +++ b/src/utils/rpc/http.ts @@ -14,24 +14,28 @@ import { stringify } from '../stringify.js' import { idCache } from './id.js' export type HttpRpcClientOptions = { - // Request configuration to pass to `fetch`. + /** Request configuration to pass to `fetch`. */ fetchOptions?: Omit | undefined - // A callback to handle the response. + /** A callback to handle the request. */ + onRequest?: ((request: Request) => Promise | void) | undefined + /** A callback to handle the response. */ onResponse?: ((response: Response) => Promise | void) | undefined - // The timeout (in ms) for the request. + /** The timeout (in ms) for the request. */ timeout?: number | undefined } export type HttpRequestParameters< TBody extends RpcRequest | RpcRequest[] = RpcRequest, > = { - // The RPC request body. + /** The RPC request body. */ body: TBody - // Request configuration to pass to `fetch`. + /** Request configuration to pass to `fetch`. */ fetchOptions?: HttpRpcClientOptions['fetchOptions'] | undefined - // A callback to handle the response. + /** A callback to handle the response. */ + onRequest?: ((request: Request) => Promise | void) | undefined + /** A callback to handle the response. */ onResponse?: ((response: Response) => Promise | void) | undefined - // The timeout (in ms) for the request. + /** The timeout (in ms) for the request. */ timeout?: HttpRpcClientOptions['timeout'] | undefined } @@ -60,6 +64,7 @@ export function getHttpRpcClient( const { body, fetchOptions = {}, + onRequest = options.onRequest, onResponse = options.onResponse, timeout = options.timeout ?? 10_000, } = params @@ -72,7 +77,7 @@ export function getHttpRpcClient( try { const response = await withTimeout( async ({ signal }) => { - const response = await fetch(url, { + const request = new Request(url, { ...fetchOptions, body: Array.isArray(body) ? stringify( @@ -94,6 +99,8 @@ export function getHttpRpcClient( method: method || 'POST', signal: signal_ || (timeout > 0 ? signal : null), }) + if (onRequest) await onRequest(request) + const response = await fetch(request) return response }, { @@ -108,11 +115,9 @@ export function getHttpRpcClient( let data: any if ( response.headers.get('Content-Type')?.startsWith('application/json') - ) { + ) data = await response.json() - } else { - data = await response.text() - } + else data = await response.text() if (!response.ok) { throw new HttpRequestError({ From 70f3f2edf66a48e017a61b1c08d4d3b9452f6c54 Mon Sep 17 00:00:00 2001 From: Tom Meagher Date: Sat, 30 Mar 2024 12:50:31 -0400 Subject: [PATCH 2/5] chore: changeset --- .changeset/chatty-berries-brake.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/chatty-berries-brake.md diff --git a/.changeset/chatty-berries-brake.md b/.changeset/chatty-berries-brake.md new file mode 100644 index 0000000000..e753fb5a39 --- /dev/null +++ b/.changeset/chatty-berries-brake.md @@ -0,0 +1,5 @@ +--- +"viem": patch +--- + +Added `onFetchRequest` to `http` transport. From b8fe3e492df9bf4e854b67b0e15bbd2f472902f5 Mon Sep 17 00:00:00 2001 From: Tom Meagher Date: Sat, 30 Mar 2024 12:51:33 -0400 Subject: [PATCH 3/5] test: add --- src/clients/transports/http.test.ts | 2 +- src/utils/rpc/http.test.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/clients/transports/http.test.ts b/src/clients/transports/http.test.ts index 9a6fec62c9..72f6492bb6 100644 --- a/src/clients/transports/http.test.ts +++ b/src/clients/transports/http.test.ts @@ -271,7 +271,7 @@ describe('request', () => { await server.close() }) - test.only('behavior: onFetchRequest', async () => { + test('behavior: onFetchRequest', async () => { const server = await createHttpServer((_, res) => { res.end(JSON.stringify({ result: '0x1' })) }) diff --git a/src/utils/rpc/http.test.ts b/src/utils/rpc/http.test.ts index 36eafae31c..c690d048bf 100644 --- a/src/utils/rpc/http.test.ts +++ b/src/utils/rpc/http.test.ts @@ -151,6 +151,32 @@ describe('request', () => { await server.close() }) + test('onRequest', async () => { + const server = await createHttpServer((_, res) => { + res.end(JSON.stringify({ result: '0x1' })) + }) + + const requests: Request[] = [] + const client = getHttpRpcClient(server.url, { + onRequest: (request) => { + requests.push(request) + }, + }) + await client.request({ + body: { method: 'web3_clientVersion' }, + }) + await client.request({ + body: { method: 'web3_clientVersion' }, + onRequest: (request) => { + requests.push(request) + }, + }) + + expect(requests.length).toBe(2) + + await server.close() + }) + test('onResponse', async () => { const server = await createHttpServer((_, res) => { res.end(JSON.stringify({ result: '0x1' })) From d74e39a51c9e189b27b5be45c6d595e48f3e3cf4 Mon Sep 17 00:00:00 2001 From: Tom Meagher Date: Sat, 30 Mar 2024 13:43:01 -0400 Subject: [PATCH 4/5] chore: snaps --- src/utils/rpc/http.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/rpc/http.test.ts b/src/utils/rpc/http.test.ts index c690d048bf..c174e1e8af 100644 --- a/src/utils/rpc/http.test.ts +++ b/src/utils/rpc/http.test.ts @@ -329,12 +329,12 @@ describe('http (batch)', () => { ).toMatchInlineSnapshot(` [ { - "id": 70, + "id": 74, "jsonrpc": "2.0", "result": "anvil/v0.2.0", }, { - "id": 71, + "id": 75, "jsonrpc": "2.0", "result": "anvil/v0.2.0", }, From 6dbe04042158ebd448bb61f0a965de106a22203c Mon Sep 17 00:00:00 2001 From: jxom Date: Mon, 1 Apr 2024 08:18:16 +1100 Subject: [PATCH 5/5] Update http.test.ts --- src/clients/transports/http.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/clients/transports/http.test.ts b/src/clients/transports/http.test.ts index 72f6492bb6..69b99f49d9 100644 --- a/src/clients/transports/http.test.ts +++ b/src/clients/transports/http.test.ts @@ -286,7 +286,6 @@ describe('request', () => { await transport.request({ method: 'eth_blockNumber' }) - console.log(requests) expect(requests.length).toBe(1) await server.close()