Skip to content

Commit aa01dfd

Browse files
using anyhow to propagate errors instead of panicking
1 parent 1c7c55e commit aa01dfd

File tree

3 files changed

+57
-59
lines changed

3 files changed

+57
-59
lines changed

discounts/rust/discounts/default/Cargo.toml.liquid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ serde = { version = "1.0.13", features = ["derive"] }
88
serde_json = "1.0"
99
shopify_function = "0.8.1"
1010
graphql_client = "0.14.0"
11+
anyhow = "1.0.93"
1112

1213
[profile.release]
1314
lto = true

discounts/rust/discounts/default/src/fetch.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use serde_json::json;
1+
use serde::Serialize;
22
use shopify_function::prelude::*;
33
use shopify_function::Result;
44

@@ -18,24 +18,30 @@ type DeliveryFetchResponseData = delivery_fetch::input::ResponseData;
1818
type CartHttpRequestHeader = cart_fetch::output::HttpRequestHeader;
1919
type DeliveryHttpRequestHeader = delivery_fetch::output::HttpRequestHeader;
2020

21+
#[derive(Serialize)]
22+
#[serde(rename_all = "camelCase")]
23+
struct RequestBody {
24+
entered_discount_codes: Vec<String>,
25+
}
26+
2127
#[shopify_function_target(
2228
target = "cart_fetch",
2329
query_path = "src/fetch.graphql",
2430
schema_path = "schema.graphql"
2531
)]
2632
fn cart_fetch(input: CartFetchResponseData) -> Result<FunctionCartFetchResult> {
27-
let body = json!({
28-
"enteredDiscountCodes": input.entered_discount_codes
29-
});
33+
let request_body = RequestBody {
34+
entered_discount_codes: input.entered_discount_codes,
35+
};
3036

3137
Ok(FunctionCartFetchResult {
3238
request: Some(CartHttpRequest {
33-
body: Some(body.to_string()),
39+
body: Some(serde_json::to_string(&request_body)?),
3440
headers: vec![CartHttpRequestHeader {
3541
name: "Accept".to_string(),
3642
value: "application/json; charset=utf-8".to_string(),
3743
}],
38-
json_body: Some(body.clone()),
44+
json_body: Some(serde_json::to_value(&request_body)?),
3945
method: CartHttpRequestMethod::POST,
4046
policy: CartHttpRequestPolicy {
4147
read_timeout_ms: 2000,
@@ -51,18 +57,18 @@ fn cart_fetch(input: CartFetchResponseData) -> Result<FunctionCartFetchResult> {
5157
schema_path = "schema.graphql"
5258
)]
5359
fn delivery_fetch(input: DeliveryFetchResponseData) -> Result<FunctionDeliveryFetchResult> {
54-
let body = json!({
55-
"enteredDiscountCodes": input.entered_discount_codes
56-
});
60+
let request_body = RequestBody {
61+
entered_discount_codes: input.entered_discount_codes,
62+
};
5763

5864
Ok(FunctionDeliveryFetchResult {
5965
request: Some(DeliveryHttpRequest {
60-
body: Some(body.to_string()),
66+
body: Some(serde_json::to_string(&request_body)?),
6167
headers: vec![DeliveryHttpRequestHeader {
6268
name: "Accept".to_string(),
6369
value: "application/json; charset=utf-8".to_string(),
6470
}],
65-
json_body: Some(body.clone()),
71+
json_body: Some(serde_json::to_value(&request_body)?),
6672
method: DeliveryHttpRequestMethod::POST,
6773
policy: DeliveryHttpRequestPolicy {
6874
read_timeout_ms: 2000,
@@ -75,6 +81,7 @@ fn delivery_fetch(input: DeliveryFetchResponseData) -> Result<FunctionDeliveryFe
7581
#[cfg(test)]
7682
mod tests {
7783
use super::*;
84+
use serde_json::json;
7885
use shopify_function::{run_function_with_input, Result};
7986

8087
fn get_fetch_input_json() -> serde_json::Value {

discounts/rust/discounts/default/src/run.rs

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use anyhow::Context;
12
use serde::Deserialize;
23

34
use shopify_function::prelude::*;
@@ -26,53 +27,44 @@ type CartResponseData = cart_run::input::ResponseData;
2627
type DeliveryResponseData = delivery_run::input::ResponseData;
2728

2829
impl CartResponseData {
29-
fn metafield(&self) -> Metafield {
30-
self.discount_node
30+
fn metafield(&self) -> anyhow::Result<Metafield> {
31+
let metafield = self
32+
.discount_node
3133
.metafield
3234
.as_ref()
33-
.map(|metafield| serde_json::from_str(&metafield.value))
34-
.unwrap()
35-
.expect("Missing required metafield configuration")
35+
.context("Missing metafield")?;
36+
serde_json::from_str(&metafield.value).context("Metafield value cannot be parsed")
3637
}
37-
fn valid_discount_codes(&self) -> Vec<String> {
38-
self.fetch_result
39-
.as_ref()
40-
.unwrap()
41-
.body
42-
.as_ref()
43-
.map(|available_codes| serde_json::from_str(available_codes))
44-
.unwrap()
45-
.expect("Missing required metafield configuration")
38+
fn valid_discount_codes(&self) -> anyhow::Result<Vec<String>> {
39+
let fetch_result = self.fetch_result.as_ref().context("Missing fetch result")?;
40+
let body = fetch_result.body.as_ref().context("Missing body")?;
41+
serde_json::from_str(body).context("Fetch result body cannot be parsed")
4642
}
4743
}
4844

4945
impl DeliveryResponseData {
50-
fn metafield(&self) -> Metafield {
51-
self.discount_node
46+
fn metafield(&self) -> anyhow::Result<Metafield> {
47+
let metafield = &self
48+
.discount_node
5249
.metafield
5350
.as_ref()
54-
.map(|metafield| serde_json::from_str(&metafield.value))
55-
.unwrap()
56-
.expect("Missing required metafield configuration")
51+
.context("Missing metafield")?;
52+
serde_json::from_str(&metafield.value).context("Metafield value cannot be parsed")
5753
}
5854

59-
fn valid_discount_codes(&self) -> Vec<String> {
60-
self.fetch_result
61-
.as_ref()
62-
.unwrap()
63-
.body
64-
.as_ref()
65-
.map(|available_codes| serde_json::from_str(available_codes))
66-
.unwrap()
67-
.expect("Missing required metafield configuration")
55+
fn valid_discount_codes(&self) -> anyhow::Result<Vec<String>> {
56+
let fetch_result = self.fetch_result.as_ref().expect("Missing fetch result");
57+
let body = fetch_result.body.as_ref().expect("Missing body");
58+
serde_json::from_str(body).context("Fetch result body cannot be parsed")
6859
}
6960
}
7061

7162
#[derive(Deserialize)]
63+
#[serde(rename_all = "camelCase")]
7264
struct Metafield {
73-
cart_percent: Option<Decimal>,
74-
product_percent: Option<Decimal>,
75-
delivery_percent: Option<Decimal>,
65+
order_percentage: Option<Decimal>,
66+
product_percentage: Option<Decimal>,
67+
delivery_percentage: Option<Decimal>,
7668
}
7769

7870
#[shopify_function_target(
@@ -81,15 +73,14 @@ struct Metafield {
8173
schema_path = "schema.graphql"
8274
)]
8375
fn cart_run(input: CartResponseData) -> Result<FunctionCartRunResult> {
84-
let default = FunctionCartRunResult { operations: vec![] };
85-
let codes = input.valid_discount_codes();
76+
let codes = input.valid_discount_codes()?;
8677
let available_discount_code = codes.first();
8778

8879
if available_discount_code.is_none() {
89-
return Ok(default);
80+
return Ok(FunctionCartRunResult { operations: vec![] });
9081
}
9182

92-
let metafield = input.metafield();
83+
let metafield = input.metafield()?;
9384
let mut operations: Vec<CartOperation> = vec![];
9485
let available_discount_code = available_discount_code.unwrap();
9586

@@ -101,11 +92,11 @@ fn cart_run(input: CartResponseData) -> Result<FunctionCartRunResult> {
10192
},
10293
));
10394

104-
if metafield.cart_percent.is_some() {
95+
if metafield.order_percentage.is_some() {
10596
operations.push(create_order_discount(&metafield, available_discount_code));
10697
}
10798

108-
if metafield.product_percent.is_some() {
99+
if metafield.product_percentage.is_some() {
109100
let highest_priced_line = input
110101
.cart
111102
.lines
@@ -132,13 +123,12 @@ fn cart_run(input: CartResponseData) -> Result<FunctionCartRunResult> {
132123
schema_path = "schema.graphql"
133124
)]
134125
fn delivery_run(input: DeliveryResponseData) -> Result<FunctionDeliveryRunResult> {
135-
let default = FunctionDeliveryRunResult { operations: vec![] };
136-
let codes = input.valid_discount_codes();
126+
let codes = input.valid_discount_codes()?;
137127
let available_discount_code = codes.first();
138-
let metafield = input.metafield();
128+
let metafield = input.metafield()?;
139129

140-
if available_discount_code.is_none() || metafield.delivery_percent.is_none() {
141-
return Ok(default);
130+
if available_discount_code.is_none() || metafield.delivery_percentage.is_none() {
131+
return Ok(FunctionDeliveryRunResult { operations: vec![] });
142132
}
143133

144134
let mut operations: Vec<DeliveryOperation> = vec![];
@@ -183,7 +173,7 @@ fn create_order_discount(metafield: &Metafield, available_discount_code: &str) -
183173
}),
184174
message: None,
185175
value: OrderDiscountCandidateValue::Percentage(CartPercentage {
186-
value: metafield.cart_percent.unwrap(),
176+
value: metafield.order_percentage.unwrap(),
187177
}),
188178
conditions: None,
189179
}],
@@ -207,7 +197,7 @@ fn create_product_discount(
207197
}),
208198
message: None,
209199
value: ProductDiscountCandidateValue::Percentage(CartPercentage {
210-
value: metafield.product_percent.unwrap(),
200+
value: metafield.product_percentage.unwrap(),
211201
}),
212202
}],
213203
})
@@ -225,7 +215,7 @@ fn create_delivery_discount_candidate(
225215
},
226216
)],
227217
value: DeliveryDiscountCandidateValue::Percentage(DeliveryPercentage {
228-
value: metafield.delivery_percent.unwrap(),
218+
value: metafield.delivery_percentage.unwrap(),
229219
}),
230220
message: None,
231221
associated_discount_code: Some(DeliveryAssociatedDiscountCode {
@@ -271,9 +261,9 @@ mod tests {
271261
"discountNode": {
272262
"metafield": {
273263
"value": json!({
274-
"cart_percent": "10",
275-
"product_percent": "20",
276-
"delivery_percent": "30",
264+
"orderPercentage": "10",
265+
"productPercentage": "20",
266+
"deliveryPercentage": "30",
277267
}).to_string(),
278268
}
279269
},

0 commit comments

Comments
 (0)