From b0d58a3dac5cb5a9708ebdbc1cd5f9c9c442901f Mon Sep 17 00:00:00 2001 From: Alberto Vena Date: Wed, 20 Nov 2024 21:45:17 +0100 Subject: [PATCH] Extend webhook registration to support filters With this change, we can register webhooks specifying the filter parameter that allows to define some conditions on the topic fields to reduce the number of webhooks received. Other than adding this feature for already possible registrations, this extends the number of webhooks that can be registered with this library. In fact, there are some webhook registrations that require the filter parameter to be passed to allow the registrationi (this is partly an assumption because I couldn't find proper documentation around this topic). An example is METAOBJECTS_CREATE, which, without the filter param set, ``` mutation webhookSubscriptionCreate($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) { webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) { webhookSubscription { topic filter } userErrors { field message } } } { "topic": "METAOBJECTS_CREATE", "webhookSubscription": { "callbackUrl": "https://test5.com" } } ``` gives the following error: ``` { "data": { "webhookSubscriptionCreate": { "webhookSubscription": null, "userErrors": [ { "field": [ "webhookSubscription" ], "message": "The specified filter is invalid, please ensure you specify the field(s) you wish to filter on." } ] } } } ``` While with the filter on, works as expected. --- This change has been made available to 2024-07 and 2024-10, which are the versions with the filter parameter available, according to the GraphQL documentation. --- Refs: - https://shopify.dev/docs/apps/build/webhooks/customize/filters - https://shopify.dev/docs/api/admin-graphql/2024-07/input-objects/WebhookSubscriptionInput - https://shopify.dev/docs/api/admin-graphql/2024-10/input-objects/WebhookSubscriptionInput --- CHANGELOG.md | 1 + docs/usage/webhooks.md | 11 ++ .../rest/resources/2024_07/webhook.rb | 1 + .../rest/resources/2024_10/webhook.rb | 1 + lib/shopify_api/webhooks/registration.rb | 11 +- .../webhooks/registrations/event_bridge.rb | 9 +- .../webhooks/registrations/http.rb | 9 +- .../webhooks/registrations/pub_sub.rb | 8 +- lib/shopify_api/webhooks/registry.rb | 14 +- test/webhooks/registry_test.rb | 26 ++- test/webhooks/registry_test_queries.rb | 176 +++++++++++++++++- 11 files changed, 249 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e58208e8..b7d17277f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Note: For changes to the API, see https://shopify.dev/changelog?filter=api ## Unreleased +- [#1347](https://github.com/Shopify/shopify-api-ruby/pull/1347) Extend webhook registration to support filters - [#1344](https://github.com/Shopify/shopify-api-ruby/pull/1344) Allow ShopifyAPI::Webhooks::Registry to update a webhook when fields or metafield_namespaces are changed. - [#1343](https://github.com/Shopify/shopify-api-ruby/pull/1343) Make ShopifyAPI::Context::scope parameter optional. `scope` defaults to empty list `[]`. diff --git a/docs/usage/webhooks.md b/docs/usage/webhooks.md index 55665ebee..32b940e08 100644 --- a/docs/usage/webhooks.md +++ b/docs/usage/webhooks.md @@ -82,6 +82,17 @@ registration = ShopifyAPI::Webhooks::Registry.add_registration( ) ``` +If you need to filter the webhooks you want to receive, you can use a [webhooks filter](https://shopify.dev/docs/apps/build/webhooks/customize/filters), which can be specified on registration through the `filter` parameter. + +```ruby +registration = ShopifyAPI::Webhooks::Registry.add_registration( + topic: "products/update", + delivery_method: :http, + handler: WebhookHandler, + filter: "variants.price:>=10.00" +) +``` + **Note**: The webhooks you register with Shopify are saved in the Shopify platform, but the local `ShopifyAPI::Webhooks::Registry` needs to be reloaded whenever your server restarts. ### EventBridge and PubSub Webhooks diff --git a/lib/shopify_api/rest/resources/2024_07/webhook.rb b/lib/shopify_api/rest/resources/2024_07/webhook.rb index c78827aee..21f5bbf0f 100644 --- a/lib/shopify_api/rest/resources/2024_07/webhook.rb +++ b/lib/shopify_api/rest/resources/2024_07/webhook.rb @@ -23,6 +23,7 @@ def initialize(session: ShopifyAPI::Context.active_session, from_hash: nil) @api_version = T.let(nil, T.nilable(String)) @created_at = T.let(nil, T.nilable(String)) @fields = T.let(nil, T.nilable(T::Array[T.untyped])) + @filter = T.let(nil, T.nilable(String)) @format = T.let(nil, T.nilable(String)) @id = T.let(nil, T.nilable(Integer)) @metafield_namespaces = T.let(nil, T.nilable(T::Array[T.untyped])) diff --git a/lib/shopify_api/rest/resources/2024_10/webhook.rb b/lib/shopify_api/rest/resources/2024_10/webhook.rb index c78827aee..21f5bbf0f 100644 --- a/lib/shopify_api/rest/resources/2024_10/webhook.rb +++ b/lib/shopify_api/rest/resources/2024_10/webhook.rb @@ -23,6 +23,7 @@ def initialize(session: ShopifyAPI::Context.active_session, from_hash: nil) @api_version = T.let(nil, T.nilable(String)) @created_at = T.let(nil, T.nilable(String)) @fields = T.let(nil, T.nilable(T::Array[T.untyped])) + @filter = T.let(nil, T.nilable(String)) @format = T.let(nil, T.nilable(String)) @id = T.let(nil, T.nilable(Integer)) @metafield_namespaces = T.let(nil, T.nilable(T::Array[T.untyped])) diff --git a/lib/shopify_api/webhooks/registration.rb b/lib/shopify_api/webhooks/registration.rb index 8cd18d543..b406aea61 100644 --- a/lib/shopify_api/webhooks/registration.rb +++ b/lib/shopify_api/webhooks/registration.rb @@ -22,18 +22,23 @@ class Registration sig { returns(T.nilable(T::Array[String])) } attr_reader :metafield_namespaces + sig { returns(T.nilable(String)) } + attr_reader :filter + sig do params(topic: String, path: String, handler: T.nilable(T.any(Handler, WebhookHandler)), fields: T.nilable(T.any(String, T::Array[String])), - metafield_namespaces: T.nilable(T::Array[String])).void + metafield_namespaces: T.nilable(T::Array[String]), + filter: T.nilable(String)).void end - def initialize(topic:, path:, handler: nil, fields: nil, metafield_namespaces: nil) + def initialize(topic:, path:, handler: nil, fields: nil, metafield_namespaces: nil, filter: nil) @topic = T.let(topic.gsub("/", "_").upcase, String) @path = path @handler = handler fields_array = fields.is_a?(String) ? fields.split(FIELDS_DELIMITER) : fields @fields = T.let(fields_array&.map(&:strip)&.compact, T.nilable(T::Array[String])) @metafield_namespaces = T.let(metafield_namespaces&.map(&:strip)&.compact, T.nilable(T::Array[String])) + @filter = filter end sig { abstract.returns(String) } @@ -54,6 +59,7 @@ def build_check_query; end current_address: T.nilable(String), fields: T::Array[String], metafield_namespaces: T::Array[String], + filter: T.nilable(String), }) end def parse_check_result(body); end @@ -88,6 +94,7 @@ def subscription_response_attributes attributes = ["id"] attributes << "includeFields" if @fields attributes << "metafieldNamespaces" if @metafield_namespaces + attributes << "filter" if @filter attributes end end diff --git a/lib/shopify_api/webhooks/registrations/event_bridge.rb b/lib/shopify_api/webhooks/registrations/event_bridge.rb index 8a3653f4b..f5f02afea 100644 --- a/lib/shopify_api/webhooks/registrations/event_bridge.rb +++ b/lib/shopify_api/webhooks/registrations/event_bridge.rb @@ -14,7 +14,8 @@ def callback_address sig { override.returns(T::Hash[Symbol, String]) } def subscription_args - { arn: callback_address, includeFields: fields, metafieldNamespaces: metafield_namespaces }.compact + { arn: callback_address, includeFields: fields, + metafieldNamespaces: metafield_namespaces, filter: filter, }.compact end sig { override.params(webhook_id: T.nilable(String)).returns(String) } @@ -32,6 +33,7 @@ def build_check_query id includeFields metafieldNamespaces + filter endpoint { __typename ... on WebhookEventBridgeEndpoint { @@ -51,6 +53,7 @@ def build_check_query current_address: T.nilable(String), fields: T::Array[String], metafield_namespaces: T::Array[String], + filter: T.nilable(String), }) end def parse_check_result(body) @@ -58,6 +61,7 @@ def parse_check_result(body) webhook_id = nil fields = [] metafield_namespaces = [] + filter = nil current_address = nil unless edges.empty? node = edges[0]["node"] @@ -65,9 +69,10 @@ def parse_check_result(body) current_address = node["endpoint"]["arn"].to_s fields = node["includeFields"] || [] metafield_namespaces = node["metafieldNamespaces"] || [] + filter = node["filter"].to_s end { webhook_id: webhook_id, current_address: current_address, fields: fields, - metafield_namespaces: metafield_namespaces, } + metafield_namespaces: metafield_namespaces, filter: filter, } end end end diff --git a/lib/shopify_api/webhooks/registrations/http.rb b/lib/shopify_api/webhooks/registrations/http.rb index a3c0cf48a..4e4459b8d 100644 --- a/lib/shopify_api/webhooks/registrations/http.rb +++ b/lib/shopify_api/webhooks/registrations/http.rb @@ -20,7 +20,8 @@ def callback_address sig { override.returns(T::Hash[Symbol, String]) } def subscription_args - { callbackUrl: callback_address, includeFields: fields, metafieldNamespaces: metafield_namespaces }.compact + { callbackUrl: callback_address, includeFields: fields, + metafieldNamespaces: metafield_namespaces, filter: filter, }.compact end sig { override.params(webhook_id: T.nilable(String)).returns(String) } @@ -38,6 +39,7 @@ def build_check_query id includeFields metafieldNamespaces + filter endpoint { __typename ... on WebhookHttpEndpoint { @@ -57,6 +59,7 @@ def build_check_query current_address: T.nilable(String), fields: T::Array[String], metafield_namespaces: T::Array[String], + filter: T.nilable(String), }) end def parse_check_result(body) @@ -64,6 +67,7 @@ def parse_check_result(body) webhook_id = nil fields = [] metafield_namespaces = [] + filter = nil current_address = nil unless edges.empty? node = edges[0]["node"] @@ -76,9 +80,10 @@ def parse_check_result(body) end fields = node["includeFields"] || [] metafield_namespaces = node["metafieldNamespaces"] || [] + filter = node["filter"].to_s end { webhook_id: webhook_id, current_address: current_address, fields: fields, - metafield_namespaces: metafield_namespaces, } + metafield_namespaces: metafield_namespaces, filter: filter, } end end end diff --git a/lib/shopify_api/webhooks/registrations/pub_sub.rb b/lib/shopify_api/webhooks/registrations/pub_sub.rb index 183ba890b..dc657964a 100644 --- a/lib/shopify_api/webhooks/registrations/pub_sub.rb +++ b/lib/shopify_api/webhooks/registrations/pub_sub.rb @@ -18,7 +18,7 @@ def subscription_args project = project_topic_pair[0] topic = project_topic_pair[1] { pubSubProject: project, pubSubTopic: topic, includeFields: fields, - metafieldNamespaces: metafield_namespaces, }.compact + metafieldNamespaces: metafield_namespaces, filter: filter, }.compact end sig { override.params(webhook_id: T.nilable(String)).returns(String) } @@ -36,6 +36,7 @@ def build_check_query id includeFields metafieldNamespaces + filter endpoint { __typename ... on WebhookPubSubEndpoint { @@ -56,6 +57,7 @@ def build_check_query current_address: T.nilable(String), fields: T::Array[String], metafield_namespaces: T::Array[String], + filter: T.nilable(String), }) end def parse_check_result(body) @@ -63,6 +65,7 @@ def parse_check_result(body) webhook_id = nil fields = [] metafield_namespaces = [] + filter = nil current_address = nil unless edges.empty? node = edges[0]["node"] @@ -71,9 +74,10 @@ def parse_check_result(body) "pubsub://#{node["endpoint"]["pubSubProject"]}:#{node["endpoint"]["pubSubTopic"]}" fields = node["includeFields"] || [] metafield_namespaces = node["metafieldNamespaces"] || [] + filter = node["filter"].to_s end { webhook_id: webhook_id, current_address: current_address, fields: fields, - metafield_namespaces: metafield_namespaces, } + metafield_namespaces: metafield_namespaces, filter: filter, } end end end diff --git a/lib/shopify_api/webhooks/registry.rb b/lib/shopify_api/webhooks/registry.rb index d6abb8d44..8cc26aab9 100644 --- a/lib/shopify_api/webhooks/registry.rb +++ b/lib/shopify_api/webhooks/registry.rb @@ -19,23 +19,25 @@ class << self path: String, handler: T.nilable(T.any(Handler, WebhookHandler)), fields: T.nilable(T.any(String, T::Array[String])), + filter: T.nilable(String), metafield_namespaces: T.nilable(T::Array[String])).void end - def add_registration(topic:, delivery_method:, path:, handler: nil, fields: nil, metafield_namespaces: nil) + def add_registration(topic:, delivery_method:, path:, handler: nil, fields: nil, filter: nil, + metafield_namespaces: nil) @registry[topic] = case delivery_method when :pub_sub Registrations::PubSub.new(topic: topic, path: path, fields: fields, - metafield_namespaces: metafield_namespaces) + metafield_namespaces: metafield_namespaces, filter: filter) when :event_bridge Registrations::EventBridge.new(topic: topic, path: path, fields: fields, - metafield_namespaces: metafield_namespaces) + metafield_namespaces: metafield_namespaces, filter: filter) when :http unless handler raise Errors::InvalidWebhookRegistrationError, "Cannot create an Http registration without a handler." end Registrations::Http.new(topic: topic, path: path, handler: handler, - fields: fields, metafield_namespaces: metafield_namespaces) + fields: fields, metafield_namespaces: metafield_namespaces, filter: filter) else raise Errors::InvalidWebhookRegistrationError, "Unsupported delivery method #{delivery_method}. Allowed values: {:http, :pub_sub, :event_bridge}." @@ -223,10 +225,12 @@ def webhook_registration_needed?(client, registration) parsed_check_result = registration.parse_check_result(T.cast(check_response.body, T::Hash[String, T.untyped])) registration_fields = registration.fields || [] registration_metafield_namespaces = registration.metafield_namespaces || [] + registration_filter = registration.filter must_register = parsed_check_result[:current_address] != registration.callback_address || parsed_check_result[:fields].sort != registration_fields.sort || - parsed_check_result[:metafield_namespaces].sort != registration_metafield_namespaces.sort + parsed_check_result[:metafield_namespaces].sort != registration_metafield_namespaces.sort || + parsed_check_result[:filter] != registration_filter { webhook_id: parsed_check_result[:webhook_id], must_register: must_register } end diff --git a/test/webhooks/registry_test.rb b/test/webhooks/registry_test.rb index 6a852a9d6..a2c0dec84 100644 --- a/test/webhooks/registry_test.rb +++ b/test/webhooks/registry_test.rb @@ -53,6 +53,7 @@ def setup address, fields: "field1, field2", metafield_namespaces: ["namespace1", "namespace2"], + filter: "id:*", ) # Then @@ -72,6 +73,7 @@ def setup address, fields: ["field1", "field2"], metafield_namespaces: ["namespace1", "namespace2"], + filter: "id:*", ) # Then @@ -156,6 +158,27 @@ def setup update_registration_response.body) end + define_method("test_#{protocol}_update_registration_filter_with_address_#{address}") do + # Given + setup_queries_and_responses( + [queries[protocol][:check_query], queries[protocol][:register_update_query_with_filter]], + [queries[protocol][:check_existing_response], + queries[protocol][:register_update_with_filter_response],], + ) + + # When + update_registration_response = add_and_register_webhook( + protocol, + address, + filter: "id:*", + ) + + # Then + assert(update_registration_response.success) + assert_equal(queries[protocol][:register_update_with_filter_response], + update_registration_response.body) + end + define_method("test_raises_on_#{protocol}_registration_check_error_with_address_#{address}") do # Given ShopifyAPI::Webhooks::Registry.clear @@ -412,7 +435,7 @@ def setup_queries_and_responses(queries, responses) end end - def add_and_register_webhook(protocol, address, fields: nil, metafield_namespaces: nil) + def add_and_register_webhook(protocol, address, fields: nil, metafield_namespaces: nil, filter: nil) ShopifyAPI::Webhooks::Registry.add_registration( topic: @topic, delivery_method: protocol, @@ -423,6 +446,7 @@ def add_and_register_webhook(protocol, address, fields: nil, metafield_namespace ), fields: fields, metafield_namespaces: metafield_namespaces, + filter: filter, ) update_registration_response = ShopifyAPI::Webhooks::Registry.register_all( session: @session, diff --git a/test/webhooks/registry_test_queries.rb b/test/webhooks/registry_test_queries.rb index ddb186310..c2bebe651 100644 --- a/test/webhooks/registry_test_queries.rb +++ b/test/webhooks/registry_test_queries.rb @@ -16,6 +16,7 @@ def queries id includeFields metafieldNamespaces + filter endpoint { __typename ... on WebhookHttpEndpoint { @@ -38,7 +39,7 @@ def queries register_add_query: <<~QUERY, mutation webhookSubscription { - webhookSubscriptionCreate(topic: SOME_TOPIC, webhookSubscription: {callbackUrl: "https://app-address.com/test-webhooks", includeFields: ["field1", "field2"], metafieldNamespaces: ["namespace1", "namespace2"]}) { + webhookSubscriptionCreate(topic: SOME_TOPIC, webhookSubscription: {callbackUrl: "https://app-address.com/test-webhooks", includeFields: ["field1", "field2"], metafieldNamespaces: ["namespace1", "namespace2"], filter: "id:*"}) { userErrors { field message @@ -47,6 +48,7 @@ def queries id includeFields metafieldNamespaces + filter } } } @@ -82,6 +84,22 @@ def queries } QUERY + register_add_query_with_filter: + <<~QUERY, + mutation webhookSubscription { + webhookSubscriptionCreate(topic: SOME_TOPIC, webhookSubscription: {callbackUrl: "https://app-address.com/test-webhooks", filter: "id:*"}) { + userErrors { + field + message + } + webhookSubscription { + id + filter + } + } + } + QUERY + register_add_response: { "data" => { "webhookSubscriptionCreate" => { @@ -90,6 +108,7 @@ def queries "id" => "gid://shopify/WebhookSubscription/12345", "includeFields" => ["field1", "field2"], "metafieldNamespaces" => ["namespace1", "namespace2"], + "filter" => "id:*", }, }, }, @@ -116,6 +135,17 @@ def queries }, }, }, + register_add_with_filter_response: { + "data" => { + "webhookSubscriptionCreate" => { + "userErrors" => [], + "webhookSubscription" => { + "id" => "gid://shopify/WebhookSubscription/12345", + "filter" => "id:*", + }, + }, + }, + }, check_existing_response: { "data" => { "webhookSubscriptions" => { @@ -139,6 +169,7 @@ def queries "id" => "gid://shopify/WebhookSubscription/12345", "includeFields" => ["field1", "field2"], "metafieldNamespaces" => ["namespace1", "namespace2"], + "filter" => "id:*", "endpoint" => { "typename" => "WebhookHttpEndpoint", "callbackUrl" => "https://app-address.com/test-webhooks", @@ -192,6 +223,21 @@ def queries } } QUERY + register_update_query_with_filter: + <<~QUERY, + mutation webhookSubscription { + webhookSubscriptionUpdate(id: "gid://shopify/WebhookSubscription/12345", webhookSubscription: {callbackUrl: "https://app-address.com/test-webhooks", filter: "id:*"}) { + userErrors { + field + message + } + webhookSubscription { + id + filter + } + } + } + QUERY register_update_response: { "data" => { "webhookSubscriptionUpdate" => { @@ -223,6 +269,17 @@ def queries }, }, }, + register_update_with_filter_response: { + "data" => { + "webhookSubscriptionUpdate" => { + "userErrors" => [], + "webhookSubscription" => { + "id" => "gid://shopify/WebhookSubscription/12345", + "filter" => "id:*", + }, + }, + }, + }, }, event_bridge: { check_query: @@ -234,6 +291,7 @@ def queries id includeFields metafieldNamespaces + filter endpoint { __typename ... on WebhookEventBridgeEndpoint { @@ -255,7 +313,7 @@ def queries register_add_query: <<~QUERY, mutation webhookSubscription { - eventBridgeWebhookSubscriptionCreate(topic: SOME_TOPIC, webhookSubscription: {arn: "test-webhooks", includeFields: ["field1", "field2"], metafieldNamespaces: ["namespace1", "namespace2"]}) { + eventBridgeWebhookSubscriptionCreate(topic: SOME_TOPIC, webhookSubscription: {arn: "test-webhooks", includeFields: ["field1", "field2"], metafieldNamespaces: ["namespace1", "namespace2"], filter: "id:*"}) { userErrors { field message @@ -264,6 +322,7 @@ def queries id includeFields metafieldNamespaces + filter } } } @@ -298,6 +357,21 @@ def queries } } QUERY + register_add_query_with_filter: + <<~QUERY, + mutation webhookSubscription { + eventBridgeWebhookSubscriptionCreate(topic: SOME_TOPIC, webhookSubscription: {arn: "test-webhooks", filter: "id:*"}) { + userErrors { + field + message + } + webhookSubscription { + id + filter + } + } + } + QUERY register_add_response: { "data" => { "eventBridgeWebhookSubscriptionCreate" => { @@ -306,6 +380,7 @@ def queries "id" => "gid://shopify/WebhookSubscription/12345", "includeFields" => ["field1", "field2"], "metafieldNamespaces" => ["namespace1", "namespace2"], + "filter" => "id:*", }, }, }, @@ -332,6 +407,17 @@ def queries }, }, }, + register_add_with_filter_response: { + "data" => { + "eventBridgeWebhookSubscriptionCreate" => { + "userErrors" => [], + "webhookSubscription" => { + "id" => "gid://shopify/WebhookSubscription/12345", + "filter" => "id:*", + }, + }, + }, + }, check_existing_response: { "data" => { "webhookSubscriptions" => { @@ -359,6 +445,7 @@ def queries }, "includeFields" => ["field2", "field1"], "metafieldNamespaces" => ["namespace2", "namespace1"], + "filter" => "id:*", }, ], }, @@ -408,6 +495,21 @@ def queries } } QUERY + register_update_query_with_filter: + <<~QUERY, + mutation webhookSubscription { + eventBridgeWebhookSubscriptionUpdate(id: "gid://shopify/WebhookSubscription/12345", webhookSubscription: {arn: "test-webhooks", filter: "id:*"}) { + userErrors { + field + message + } + webhookSubscription { + id + filter + } + } + } + QUERY register_update_response: { "data" => { "eventBridgeWebhookSubscriptionUpdate" => { @@ -438,6 +540,17 @@ def queries }, }, }, + register_update_with_filter_response: { + "data" => { + "eventBridgeWebhookSubscriptionUpdate" => { + "userErrors" => [], + "webhookSubscription" => { + "id" => "gid://shopify/WebhookSubscription/12345", + "filter" => "id:*", + }, + }, + }, + }, }, pub_sub: { check_query: @@ -449,6 +562,7 @@ def queries id includeFields metafieldNamespaces + filter endpoint { __typename ... on WebhookPubSubEndpoint { @@ -471,7 +585,7 @@ def queries register_add_query: <<~QUERY, mutation webhookSubscription { - pubSubWebhookSubscriptionCreate(topic: SOME_TOPIC, webhookSubscription: {pubSubProject: "my-project-id", pubSubTopic: "my-topic-id", includeFields: ["field1", "field2"], metafieldNamespaces: ["namespace1", "namespace2"]}) { + pubSubWebhookSubscriptionCreate(topic: SOME_TOPIC, webhookSubscription: {pubSubProject: "my-project-id", pubSubTopic: "my-topic-id", includeFields: ["field1", "field2"], metafieldNamespaces: ["namespace1", "namespace2"], filter: "id:*"}) { userErrors { field message @@ -480,6 +594,7 @@ def queries id includeFields metafieldNamespaces + filter } } } @@ -514,6 +629,21 @@ def queries } } QUERY + register_add_query_with_filter: + <<~QUERY, + mutation webhookSubscription { + pubSubWebhookSubscriptionCreate(topic: SOME_TOPIC, webhookSubscription: {pubSubProject: "my-project-id", pubSubTopic: "my-topic-id", filter: "id:*"}) { + userErrors { + field + message + } + webhookSubscription { + id + filter + } + } + } + QUERY register_add_response: { "data" => { "pubSubWebhookSubscriptionCreate" => { @@ -522,6 +652,7 @@ def queries "id" => "gid://shopify/WebhookSubscription/12345", "includeFields" => ["field1", "field2"], "metafieldNamespaces" => ["namespace1", "namespace2"], + "filter" => "id:*", }, }, }, @@ -548,6 +679,17 @@ def queries }, }, }, + register_add_with_filter_response: { + "data" => { + "pubSubWebhookSubscriptionCreate" => { + "userErrors" => [], + "webhookSubscription" => { + "id" => "gid://shopify/WebhookSubscription/12345", + "filter": "id:*", + }, + }, + }, + }, check_existing_response: { "data" => { "webhookSubscriptions" => { @@ -577,6 +719,7 @@ def queries }, "includeFields" => ["field1", "field2"], "metafieldNamespaces" => ["namespace1", "namespace2"], + "filter" => "id:*", }, ], }, @@ -626,7 +769,21 @@ def queries } } QUERY - + register_update_query_with_filter: + <<~QUERY, + mutation webhookSubscription { + pubSubWebhookSubscriptionUpdate(id: "gid://shopify/WebhookSubscription/12345", webhookSubscription: {pubSubProject: "my-project-id", pubSubTopic: "my-topic-id", filter: "id:*"}) { + userErrors { + field + message + } + webhookSubscription { + id + filter + } + } + } + QUERY register_update_response: { "data" => { "pubSubWebhookSubscriptionUpdate" => { @@ -657,6 +814,17 @@ def queries }, }, }, + register_update_with_filter_response: { + "data" => { + "pubSubWebhookSubscriptionUpdate" => { + "userErrors" => [], + "webhookSubscription" => { + "id" => "gid://shopify/WebhookSubscription/12345", + "filter" => "id:*", + }, + }, + }, + }, }, fetch_id_query: <<~QUERY,