Hello,
I am trying to build a Shopify function extension in Rust.
I wished to make an API request from inside my function. To do that, Shopify provides it’s own way of handling requests.
I am following this article: https://shopify.dev/docs/apps/functions/input-output/network-access/using-network-access
src/fetch.rs
use shopify_function::prelude::*;
use shopify_function::Result;
#[shopify_function_target(query_path = "src/fetch.graphql", schema_path = "schema.graphql")]
fn fetch(input: fetch::input::ResponseData) -> Result<fetch::output::FunctionFetchResult> {
let mut request: Option<output::HttpRequest> = None;
// Network call if the buyer_identity is present
if let Some(buyer_identity) = &input.cart.buyer_identity {
// Network call if the email is present
if let Some(_email) = &buyer_identity.email {
let http_request = build_request(&input);
request = Some(http_request);
}
}
Ok(fetch::output::FunctionFetchResult { request })
}
fn build_request(input: &fetch::input::ResponseData) -> fetch::output::HttpRequest {
// Serializing the input for simple demonstration, the body can be articulated as needed.
let body = serde_json::to_string(&input).expect("Error serializing");
static SERVER_URL: &'static str = "https://subdomain.example.com/some-endpoint";
fetch::output::HttpRequest {
method: fetch::output::HttpRequestMethod::Other("POST".to_string()),
url: SERVER_URL.to_string(),
headers: [].to_vec(),
body: Some(body),
policy: fetch::output::HttpRequestPolicy {
read_timeout_ms: 20000,
},
}
}
src/fetch.graphql
query Input {
cart {
buyerIdentity {
email
isAuthenticated
}
cost {
totalAmount {
amount
currencyCode
}
}
}
}
src/run.rs
use shopify_function::prelude::*;
use shopify_function::Result;
use serde::Deserialize;
#[derive(Deserialize)]
struct ServerResponse {
errors: Vec<ServerResponseError>,
}
#[derive(Deserialize)]
struct ServerResponseError {
localized_message: String,
target: String,
}
#[shopify_function_target(query_path = "src/run.graphql", schema_path = "schema.graphql")]
fn run(input: run::input::ResponseData) -> Result<run::output::FunctionRunResult> {
// Optimization for when there are no requests.
// In this simple example, there are no fallbacks, but there is room to implement one if needed.
// See fetch.rs.
if input.fetch_result.is_none() {
return Ok(output::FunctionRunResult { errors: vec![] });
}
let fetch_result = input.fetch_result.unwrap();
// When the server returns an unexpected response.
// Optionally: Apply a local fallback error message.
if fetch_result.status != 200 {
panic!("Server response unprocessable (status)");
}
let body = fetch_result.body.as_ref().expect("Missing response body");
match serde_json::from_str::<ServerResponse>(body.as_str()) {
Ok(response) => {
let errors: Vec<run::output::FunctionError> = response
.errors
.into_iter()
.map(|error| run::output::FunctionError {
localized_message: error.localized_message,
target: error.target,
})
.rev()
.collect();
return Ok(run::output::FunctionRunResult { errors });
}
Err(_) => {
// Optionally: Apply a local fallback error message.
panic!("Server response unprocessable (serialization)");
}
}
}
src/run.graphql
query Input {
fetchResult {
status
headers {
name
value
}
body
}
}
I built and deployed this app to Shopify.
Then, I activated it from the test app’s checkout settings.
I tested it by building a sample cart and going to checkout.
But, each time it gives the same thing in the logs:
To further narrow down the issue, I checked the logs on my API server. The server isn’t receiving the HTTP request.
I am confused as to what is happening here.
All help would be appreciated.
Thank you.


