shopify_client/webhooks/
mod.rs1pub 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}