Skip to main content

WebhookRegistry

Struct WebhookRegistry 

Source
pub struct WebhookRegistry { /* private fields */ }
Expand description

Registry for managing webhook subscriptions.

WebhookRegistry stores webhook registrations in memory and provides methods to sync them with Shopify via the GraphQL Admin API.

§Two-Phase Pattern

The registry follows a two-phase pattern:

  1. Add Registration (Local): Use add_registration to store webhook configuration in the in-memory registry
  2. Register with Shopify (Remote): Use register or register_all to sync registrations with Shopify

This pattern allows apps to configure webhooks at startup and register them later when a valid session is available.

§Thread Safety

WebhookRegistry is Send + Sync, making it safe to share across threads.

§Smart Registration

When registering webhooks, the registry performs “smart registration”:

  • Queries existing subscriptions from Shopify
  • Compares configuration to detect changes
  • Only creates/updates when necessary
  • Avoids unnecessary API calls

§Delivery Methods

The registry supports three delivery methods:

  • HTTP: Webhooks delivered via HTTP POST to a callback URL
  • EventBridge: Webhooks delivered to Amazon EventBridge
  • Pub/Sub: Webhooks delivered to Google Cloud Pub/Sub

§Example

use shopify_sdk::webhooks::{WebhookRegistry, WebhookRegistrationBuilder, WebhookDeliveryMethod};
use shopify_sdk::rest::resources::v2025_10::common::WebhookTopic;

// Create a registry and add registrations
let mut registry = WebhookRegistry::new();

registry.add_registration(
    WebhookRegistrationBuilder::new(
        WebhookTopic::OrdersCreate,
        WebhookDeliveryMethod::Http {
            uri: "https://example.com/api/webhooks/orders".to_string(),
        },
    )
    .build()
);

// Later, when you have a session:
// let results = registry.register_all(&session, &config).await?;

Implementations§

Source§

impl WebhookRegistry

Source

pub fn new() -> Self

Creates a new empty webhook registry.

§Example
use shopify_sdk::webhooks::WebhookRegistry;

let registry = WebhookRegistry::new();
assert!(registry.list_registrations().is_empty());
Source

pub fn add_registration( &mut self, registration: WebhookRegistration, ) -> &mut Self

Adds a webhook registration to the registry.

If a registration for the same topic already exists, it will be replaced. If the registration contains a handler, the handler is extracted and stored separately in the handlers map. Returns &mut Self to allow method chaining.

§Arguments
  • registration - The webhook registration to add
§Example
use shopify_sdk::webhooks::{WebhookRegistry, WebhookRegistrationBuilder, WebhookDeliveryMethod};
use shopify_sdk::rest::resources::v2025_10::common::WebhookTopic;

let mut registry = WebhookRegistry::new();

// Method chaining with different delivery methods
registry
    .add_registration(
        WebhookRegistrationBuilder::new(
            WebhookTopic::OrdersCreate,
            WebhookDeliveryMethod::Http {
                uri: "https://example.com/webhooks/orders/create".to_string(),
            },
        )
        .build()
    )
    .add_registration(
        WebhookRegistrationBuilder::new(
            WebhookTopic::ProductsUpdate,
            WebhookDeliveryMethod::EventBridge {
                arn: "arn:aws:events:us-east-1::event-source/test".to_string(),
            },
        )
        .build()
    );

assert_eq!(registry.list_registrations().len(), 2);
Source

pub fn get_registration( &self, topic: &WebhookTopic, ) -> Option<&WebhookRegistration>

Gets a webhook registration by topic.

Returns None if no registration exists for the given topic.

§Arguments
  • topic - The webhook topic to look up
§Example
use shopify_sdk::webhooks::{WebhookRegistry, WebhookRegistrationBuilder, WebhookDeliveryMethod};
use shopify_sdk::rest::resources::v2025_10::common::WebhookTopic;

let mut registry = WebhookRegistry::new();
registry.add_registration(
    WebhookRegistrationBuilder::new(
        WebhookTopic::OrdersCreate,
        WebhookDeliveryMethod::Http {
            uri: "https://example.com/webhooks".to_string(),
        },
    )
    .build()
);

// Found
assert!(registry.get_registration(&WebhookTopic::OrdersCreate).is_some());

// Not found
assert!(registry.get_registration(&WebhookTopic::ProductsCreate).is_none());
Source

pub fn list_registrations(&self) -> Vec<&WebhookRegistration>

Lists all webhook registrations in the registry.

Returns a vector of references to all registrations.

§Example
use shopify_sdk::webhooks::{WebhookRegistry, WebhookRegistrationBuilder, WebhookDeliveryMethod};
use shopify_sdk::rest::resources::v2025_10::common::WebhookTopic;

let mut registry = WebhookRegistry::new();
registry
    .add_registration(
        WebhookRegistrationBuilder::new(
            WebhookTopic::OrdersCreate,
            WebhookDeliveryMethod::Http {
                uri: "https://example.com/webhooks/orders".to_string(),
            },
        )
        .build()
    )
    .add_registration(
        WebhookRegistrationBuilder::new(
            WebhookTopic::ProductsCreate,
            WebhookDeliveryMethod::PubSub {
                project_id: "my-project".to_string(),
                topic_id: "webhooks".to_string(),
            },
        )
        .build()
    );

let registrations = registry.list_registrations();
assert_eq!(registrations.len(), 2);
Source

pub async fn process( &self, config: &ShopifyConfig, request: &WebhookRequest, ) -> Result<(), WebhookError>

Processes an incoming webhook request.

This method verifies the webhook signature, looks up the appropriate handler, parses the payload, and invokes the handler.

§Flow
  1. Verify the webhook signature using verify_webhook
  2. Look up the handler by topic
  3. Parse the request body as JSON
  4. Invoke the handler with the context and payload
§Arguments
  • config - The Shopify configuration containing the API secret key
  • request - The incoming webhook request
§Errors

Returns WebhookError::InvalidHmac if signature verification fails. Returns WebhookError::NoHandlerForTopic if no handler is registered for the topic. Returns WebhookError::PayloadParseError if the body cannot be parsed as JSON. Returns any error returned by the handler.

§Example
use shopify_sdk::webhooks::{WebhookRegistry, WebhookRequest};

let registry = WebhookRegistry::new();
// ... add registrations with handlers ...

// Process incoming webhook
registry.process(&config, &request).await?;
Source

pub async fn register( &self, session: &Session, config: &ShopifyConfig, topic: &WebhookTopic, ) -> Result<WebhookRegistrationResult, WebhookError>

Registers a single webhook with Shopify.

This method performs “smart registration”:

  • Queries existing subscriptions from Shopify
  • Compares configuration to detect changes
  • Creates new subscription if none exists
  • Updates existing subscription if configuration differs
  • Returns AlreadyRegistered if configuration matches
§Arguments
  • session - The authenticated session for API calls
  • config - The SDK configuration
  • topic - The webhook topic to register
§Errors

Returns WebhookError::RegistrationNotFound if the topic is not in the registry. Returns WebhookError::GraphqlError for underlying API errors. Returns WebhookError::ShopifyError for userErrors in the response.

§Example
use shopify_sdk::webhooks::{WebhookRegistry, WebhookRegistrationBuilder, WebhookDeliveryMethod};
use shopify_sdk::rest::resources::v2025_10::common::WebhookTopic;

let mut registry = WebhookRegistry::new();
registry.add_registration(
    WebhookRegistrationBuilder::new(
        WebhookTopic::OrdersCreate,
        WebhookDeliveryMethod::Http {
            uri: "https://example.com/webhooks/orders".to_string(),
        },
    )
    .build()
);

let result = registry.register(&session, &config, &WebhookTopic::OrdersCreate).await?;
Source

pub async fn register_all( &self, session: &Session, config: &ShopifyConfig, ) -> Vec<WebhookRegistrationResult>

Registers all webhooks in the registry with Shopify.

Iterates through all registrations and calls register for each. Continues processing even if individual registrations fail.

§Arguments
  • session - The authenticated session for API calls
  • config - The SDK configuration
§Returns

A vector of results for each registration. Individual registration failures are captured in WebhookRegistrationResult::Failed.

§Example
use shopify_sdk::webhooks::{WebhookRegistry, WebhookRegistrationBuilder, WebhookRegistrationResult, WebhookDeliveryMethod};
use shopify_sdk::rest::resources::v2025_10::common::WebhookTopic;

let mut registry = WebhookRegistry::new();
registry.add_registration(/* ... */);

let results = registry.register_all(&session, &config).await;
for result in results {
    match result {
        WebhookRegistrationResult::Created { id } => println!("Created: {}", id),
        WebhookRegistrationResult::Failed(err) => println!("Failed: {}", err),
        _ => {}
    }
}
Source

pub async fn unregister( &self, session: &Session, config: &ShopifyConfig, topic: &WebhookTopic, ) -> Result<(), WebhookError>

Unregisters a webhook from Shopify.

Queries for the existing webhook subscription and deletes it.

§Arguments
  • session - The authenticated session for API calls
  • config - The SDK configuration
  • topic - The webhook topic to unregister
§Errors

Returns WebhookError::SubscriptionNotFound if the webhook doesn’t exist in Shopify. Returns WebhookError::GraphqlError for underlying API errors. Returns WebhookError::ShopifyError for userErrors in the response.

§Example
use shopify_sdk::webhooks::WebhookRegistry;
use shopify_sdk::rest::resources::v2025_10::common::WebhookTopic;

let registry = WebhookRegistry::new();
registry.unregister(&session, &config, &WebhookTopic::OrdersCreate).await?;
Source

pub async fn unregister_all( &self, session: &Session, config: &ShopifyConfig, ) -> Result<(), WebhookError>

Unregisters all webhooks in the registry from Shopify.

Iterates through all registrations and calls unregister for each. Continues processing even if individual unregistrations fail.

§Arguments
  • session - The authenticated session for API calls
  • config - The SDK configuration
§Errors

Returns the first error encountered, but continues processing all registrations.

§Example
use shopify_sdk::webhooks::WebhookRegistry;

let mut registry = WebhookRegistry::new();
// ... add registrations ...

registry.unregister_all(&session, &config).await?;

Trait Implementations§

Source§

impl Debug for WebhookRegistry

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for WebhookRegistry

Source§

fn default() -> WebhookRegistry

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more