Skip to content

Commit

Permalink
feat(utils): Add instruments to wrapFetchWithHooks (#8456)
Browse files Browse the repository at this point in the history
* feat(utils): Add instruments to `wrapFetchWithHooks`

* chore(dependencies): updated changesets for modified dependencies

* changeset

* lazy instauments

* Add tests

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Arda TANRIKULU <[email protected]>
  • Loading branch information
3 people authored Mar 5, 2025
1 parent b970e06 commit 4528794
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 173 deletions.
5 changes: 5 additions & 0 deletions .changeset/@graphql-mesh_utils-8456-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@graphql-mesh/utils": patch
---
dependencies updates:
- Added dependency [`@envelop/instruments@1.0.0-alpha-20250227122402-42e2fa806ec3b7c2936e612924b153a20c8662c3` ↗︎](https://www.npmjs.com/package/@envelop/instruments/v/1.0.0) (to `dependencies`)
7 changes: 7 additions & 0 deletions .changeset/silent-wolves-spend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@graphql-mesh/utils': minor
---

Add compatibility with new `Instruments` API of Hive Gateway. See
[Hive Gateway documentation](https://the-guild.dev/graphql/hive/docs/gateway/other-features/custom-plugins#instruments)
for more details.
1 change: 1 addition & 0 deletions packages/legacy/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"graphql": "*"
},
"dependencies": {
"@envelop/instruments": "^1.0.0",
"@graphql-mesh/cross-helpers": "^0.4.10",
"@graphql-mesh/string-interpolation": "^0.5.8",
"@graphql-mesh/types": "^0.103.21",
Expand Down
33 changes: 31 additions & 2 deletions packages/legacy/utils/src/wrapFetchWithHooks.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getInstrumented } from '@envelop/instruments';
import type { Logger, MeshFetch, OnFetchHook, OnFetchHookDone } from '@graphql-mesh/types';
import { type ExecutionRequest, type MaybePromise } from '@graphql-tools/utils';
import { handleMaybePromise, iterateAsync } from '@whatwg-node/promise-helpers';
Expand All @@ -6,8 +7,18 @@ import { DefaultLogger } from './logger.js';
export const requestIdByRequest = new WeakMap<Request, string>();
export const loggerForExecutionRequest = new WeakMap<ExecutionRequest, Logger>();

export function wrapFetchWithHooks<TContext>(onFetchHooks: OnFetchHook<TContext>[]): MeshFetch {
return function wrappedFetchFn(url, options, context, info) {
export type FetchInstruments = {
fetch?: (
payload: { executionRequest: ExecutionRequest },
wrapped: () => MaybePromise<void>,
) => MaybePromise<void>;
};

export function wrapFetchWithHooks<TContext>(
onFetchHooks: OnFetchHook<TContext>[],
instruments?: () => FetchInstruments | undefined,
): MeshFetch {
let wrappedFetchFn = function wrappedFetchFn(url, options, context, info) {
let fetchFn: MeshFetch;
let response$: MaybePromise<Response>;
const onFetchDoneHooks: OnFetchHookDone[] = [];
Expand Down Expand Up @@ -91,4 +102,22 @@ export function wrapFetchWithHooks<TContext>(onFetchHooks: OnFetchHook<TContext>
},
);
} as MeshFetch;

if (instruments) {
const originalWrappedFetch = wrappedFetchFn;
wrappedFetchFn = function wrappedFetchFn(url, options, context, info) {
const fetchInstrument = instruments()?.fetch;
const instrumentedFetch = fetchInstrument
? getInstrumented({
get executionRequest() {
return info?.executionRequest;
},
}).asyncFn(fetchInstrument, originalWrappedFetch)
: originalWrappedFetch;

return instrumentedFetch(url, options, context, info);
};
}

return wrappedFetchFn;
}
30 changes: 30 additions & 0 deletions packages/legacy/utils/test/fetch-instruments.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { GraphQLResolveInfo } from 'graphql';
import { createServerAdapter, Response } from '@whatwg-node/server';
import { wrapFetchWithHooks, type FetchInstruments } from '../src/wrapFetchWithHooks';

describe('Fetch instruments', () => {
it('should wrap fetch instruments', async () => {
await using adapter = createServerAdapter(() => Response.json({ hello: 'world' }));
let receivedExecutionRequest;
const fetchInstruments: FetchInstruments = {
fetch: async ({ executionRequest }, wrapped) => {
receivedExecutionRequest = executionRequest;
await wrapped();
},
};
const wrappedFetch = wrapFetchWithHooks(
[
({ setFetchFn }) => {
setFetchFn(adapter.fetch);
},
],
() => fetchInstruments,
);
const executionRequest = {};
const res = await wrappedFetch('http://localhost:4000', {}, {}, {
executionRequest,
} as GraphQLResolveInfo);
expect(await res.json()).toEqual({ hello: 'world' });
expect(receivedExecutionRequest).toBe(executionRequest);
});
});
Loading

0 comments on commit 4528794

Please sign in to comment.