From 6118b8970c047a30af568646a3011717f4703fb7 Mon Sep 17 00:00:00 2001 From: Brian Chen Date: Mon, 5 Aug 2024 10:36:50 -0400 Subject: [PATCH] Fix GraphQL webhook creation and support skip_empty_messages (#440) --- CHANGELOG.md | 2 ++ src/api/notify-namespace.ts | 39 +++++++++++++++++++-------------- src/types/types.ts | 19 ++++++++++++++++ test/integration/notify.test.ts | 16 +++++++++++--- 4 files changed, 56 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2431f30a..903717cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ ### Minor Changes +- Fixed a bug with `NotifyNamespace.createWebhook()` when using `WebhookType.GRAPHQL`. Also added the option use `skipEmptyMessages` when creating graphQL webhooks to skip empty blocks. + ## 3.3.1 ### Minor Changes diff --git a/src/api/notify-namespace.ts b/src/api/notify-namespace.ts index 0965d7be..11c641bd 100644 --- a/src/api/notify-namespace.ts +++ b/src/api/notify-namespace.ts @@ -345,6 +345,19 @@ export class NotifyNamespace { } ); } + /** + * Create a new {@link CustomGraphqlWebhook} to track any event on every block. + * + * @param url The URL that the webhook should send events to. + * @param type The type of webhook to create. + * @param params Parameters object containing the graphql query to be executed + * on every block + */ + createWebhook( + url: string, + type: WebhookType.GRAPHQL, + params: CustomGraphqlWebhookParams + ): Promise; /** * Create a new {@link MinedTransactionWebhook} to track mined transactions @@ -400,20 +413,6 @@ export class NotifyNamespace { params: NftWebhookParams ): Promise; - /** - * Create a new {@link CustomGraphqlWebhook} to track any event on every block. - * - * @param url The URL that the webhook should send events to. - * @param type The type of webhook to create. - * @param params Parameters object containing the graphql query to be executed - * on every block - */ - createWebhook( - url: string, - type: WebhookType.GRAPHQL, - params: CustomGraphqlWebhookParams - ): Promise; - /** * Create a new {@link AddressActivityWebhook} to track address activity. * @@ -446,10 +445,11 @@ export class NotifyNamespace { let appId; if ( type === WebhookType.MINED_TRANSACTION || - type === WebhookType.DROPPED_TRANSACTION + type === WebhookType.DROPPED_TRANSACTION || + type === WebhookType.GRAPHQL ) { if (!('appId' in params)) { - throw new Error('Transaction Webhooks require an app id.'); + throw new Error('Transaction and GraphQL Webhooks require an app id.'); } appId = params.appId; } @@ -458,6 +458,7 @@ export class NotifyNamespace { let nftFilterObj; let addresses; let graphqlQuery; + let skipEmptyMessages; if ( type === WebhookType.NFT_ACTIVITY || type === WebhookType.NFT_METADATA_UPDATE @@ -510,6 +511,7 @@ export class NotifyNamespace { ? NETWORK_TO_WEBHOOK_NETWORK.get(params.network) : network; graphqlQuery = params.graphqlQuery; + skipEmptyMessages = params.skipEmptyMessages; } const data = { @@ -521,7 +523,10 @@ export class NotifyNamespace { // Only include the filters/addresses in the final response if they're defined ...nftFilterObj, ...(addresses && { addresses }), - ...(graphqlQuery && { graphql_query: graphqlQuery }) + ...(graphqlQuery && { + graphql_query: graphqlQuery + }), + ...(skipEmptyMessages && { skip_empty_messages: skipEmptyMessages }) }; const response = await this.sendWebhookRequest( diff --git a/src/types/types.ts b/src/types/types.ts index 1864f275..ab604370 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1202,6 +1202,25 @@ export interface CustomGraphqlWebhookParams { * created on network of the app provided in the api key config. */ network?: Network; + /** + * Whether to only receive webhooks if the query on the block is not empty. + * Defaults to false. + */ + skipEmptyMessages?: boolean; + /** + * App IDs are now required for graphQL webhooks. You can find the app ID + * following the steps here: + * {@link https://docs.alchemy.com/reference/notify-api-faq#where-can-i-find-the-app-id}. + * + * The webhook will be created on the app and network associated with the appId. + * To find the app id of a project, go to the Alchemy Dashboard in the Apps tab. + * After clicking on an app, the app id is the string in the URL following 'apps/'. + * + * Note that although this property is marked as optional, it is *actually required* + * for creating a custom GraphQL webhook. This is a workaround to avoid a breaking + * change in the API. + */ + appId?: string; } /** diff --git a/test/integration/notify.test.ts b/test/integration/notify.test.ts index cec2c6af..1a9e22c6 100644 --- a/test/integration/notify.test.ts +++ b/test/integration/notify.test.ts @@ -57,7 +57,12 @@ describe('E2E integration tests', () => { customWh = await alchemy.notify.createWebhook( webhookUrl, WebhookType.GRAPHQL, - { graphqlQuery, network: Network.ETH_MAINNET } + { + graphqlQuery, + network: Network.ETH_MAINNET, + appId, + skipEmptyMessages: true + } ); } @@ -247,11 +252,16 @@ describe('E2E integration tests', () => { const customWebhook = await alchemy.notify.createWebhook( webhookUrl, WebhookType.GRAPHQL, - { graphqlQuery, network: Network.ETH_GOERLI } + { + graphqlQuery, + network: Network.ETH_MAINNET, + appId, + skipEmptyMessages: true + } ); expect(customWebhook.url).toEqual(webhookUrl); expect(customWebhook.type).toEqual(WebhookType.GRAPHQL); - expect(customWebhook.network).toEqual(Network.ETH_GOERLI); + expect(customWebhook.network).toEqual(Network.ETH_MAINNET); let response = await alchemy.notify.getAllWebhooks(); expect( response.webhooks.filter(wh => wh.id === customWebhook.id).length