shopify_client/webhooks/
mod.rs

1pub mod types;
2pub mod verify;
3
4use serde_json::Value;
5use types::{
6    CustomersDataRequestPayload, CustomersRedactPayload, ShopRedactPayload, WebhookParseError,
7    WebhookPayload,
8};
9
10pub use types::VerificationError;
11pub use verify::{verify_hmac, verify_hmac_from_headers};
12
13pub enum WebhookTopic {
14    CustomersDataRequest,
15    CustomersRedact,
16    ShopRedact,
17}
18
19impl WebhookTopic {
20    pub fn from_header(header: &str) -> Option<Self> {
21        match header.to_lowercase().as_str() {
22            "customers/data_request" => Some(WebhookTopic::CustomersDataRequest),
23            "customers/redact" => Some(WebhookTopic::CustomersRedact),
24            "shop/redact" => Some(WebhookTopic::ShopRedact),
25            _ => None,
26        }
27    }
28}
29
30pub fn parse_webhook(
31    topic: WebhookTopic,
32    payload: &str,
33) -> Result<WebhookPayload, WebhookParseError> {
34    match topic {
35        WebhookTopic::CustomersDataRequest => {
36            serde_json::from_str::<CustomersDataRequestPayload>(payload)
37                .map(WebhookPayload::CustomersDataRequest)
38                .map_err(|e| WebhookParseError::ParseError(e.to_string()))
39        }
40        WebhookTopic::CustomersRedact => serde_json::from_str::<CustomersRedactPayload>(payload)
41            .map(WebhookPayload::CustomersRedact)
42            .map_err(|e| WebhookParseError::ParseError(e.to_string())),
43        WebhookTopic::ShopRedact => serde_json::from_str::<ShopRedactPayload>(payload)
44            .map(WebhookPayload::ShopRedact)
45            .map_err(|e| WebhookParseError::ParseError(e.to_string())),
46    }
47}
48
49pub fn parse_webhook_from_value(
50    topic: WebhookTopic,
51    payload: Value,
52) -> Result<WebhookPayload, WebhookParseError> {
53    match topic {
54        WebhookTopic::CustomersDataRequest => {
55            serde_json::from_value::<CustomersDataRequestPayload>(payload)
56                .map(WebhookPayload::CustomersDataRequest)
57                .map_err(|e| WebhookParseError::ParseError(e.to_string()))
58        }
59        WebhookTopic::CustomersRedact => serde_json::from_value::<CustomersRedactPayload>(payload)
60            .map(WebhookPayload::CustomersRedact)
61            .map_err(|e| WebhookParseError::ParseError(e.to_string())),
62        WebhookTopic::ShopRedact => serde_json::from_value::<ShopRedactPayload>(payload)
63            .map(WebhookPayload::ShopRedact)
64            .map_err(|e| WebhookParseError::ParseError(e.to_string())),
65    }
66}
67
68pub fn parse_webhook_with_header(
69    topic_header: &str,
70    payload: &str,
71) -> Result<WebhookPayload, WebhookParseError> {
72    let topic =
73        WebhookTopic::from_header(topic_header).ok_or(WebhookParseError::UnknownWebhookType)?;
74    parse_webhook(topic, payload)
75}
76
77pub fn parse_webhook_with_header_from_value(
78    topic_header: &str,
79    payload: Value,
80) -> Result<WebhookPayload, WebhookParseError> {
81    let topic =
82        WebhookTopic::from_header(topic_header).ok_or(WebhookParseError::UnknownWebhookType)?;
83    parse_webhook_from_value(topic, payload)
84}
85
86pub fn try_parse_webhook(payload: &str) -> Result<WebhookPayload, WebhookParseError> {
87    if let Ok(data_request) = serde_json::from_str::<CustomersDataRequestPayload>(payload) {
88        return Ok(WebhookPayload::CustomersDataRequest(data_request));
89    }
90
91    if let Ok(customers_redact) = serde_json::from_str::<CustomersRedactPayload>(payload) {
92        return Ok(WebhookPayload::CustomersRedact(customers_redact));
93    }
94
95    if let Ok(shop_redact) = serde_json::from_str::<ShopRedactPayload>(payload) {
96        return Ok(WebhookPayload::ShopRedact(shop_redact));
97    }
98
99    Err(WebhookParseError::UnknownWebhookType)
100}
101
102pub fn try_parse_webhook_from_value(payload: Value) -> Result<WebhookPayload, WebhookParseError> {
103    if let Ok(data_request) = serde_json::from_value::<CustomersDataRequestPayload>(payload.clone())
104    {
105        return Ok(WebhookPayload::CustomersDataRequest(data_request));
106    }
107
108    if let Ok(customers_redact) = serde_json::from_value::<CustomersRedactPayload>(payload.clone())
109    {
110        return Ok(WebhookPayload::CustomersRedact(customers_redact));
111    }
112
113    if let Ok(shop_redact) = serde_json::from_value::<ShopRedactPayload>(payload) {
114        return Ok(WebhookPayload::ShopRedact(shop_redact));
115    }
116
117    Err(WebhookParseError::UnknownWebhookType)
118}