In the second post (Connecting Shopify to your computer), I went over getting to the point where Shopify is sending web traffic from their store’s admin UI to your local machine. The devastating shortcoming of the project so far is that it literally does nothing except return a 502 Bad Gateway (and even that is thanks to ngrok), which isn’t a great user experience. The next step is to… build anything at all.
Setting the Shopify configuration aside, I’ve selected the Rocket web framework because… mostly it was a coin flip. I can’t say I’m particularly overjoyed in my experience using Rocket as it’s missing quite a few things I’m used to in other frameworks, but it’s Rust and there’s just not that much on offer yet. I have opted to use the 0.5 release candidate to use stable Rust. Notably, the main developer behind the framework has some not-volunteering-his-life-for-Internet-strangers going on which has hopefully only temporarily stalled Rocket.
Lets build the worst possible Rocket application and see what happens, so here’s some code:
# Cargo.toml
[package]
name = "shopify-template2"
version = "0.1.0"
edition = "2021"
[dependencies]
rocket = "0.5.0-rc.1"
// main.rs
fn rocket() -> rocket::Rocket<rocket::Build> {
rocket::build()
}
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}
This is the reason for choosing 8000 as the port for ngrok, it’s the default used by Rocket. The the ol’ cargo run
(ensuring that ngrok is still binding to 8000) will start a Rocket server. With the server running and ngrok forwarding traffing, going back into Shopify and trying to install the app in a test store again yields yet another new kind of failure – thrilling!

And in the terminal, we see the traffic is not just making it from Shopify -> ngrok -> our machine, it’s making it to the application server as well!

Obviously it’d be surprising if Rocket worked out of the box with Shopify, so this failure is expected. Lets add an HTTP request handler so that we can start building out some functionality. At this point it does nothing but (hopefully) matches the URL Shopify is reaching out to, prints a line to the terminal, and redirects to… well, nowhere right now.
// src/main.rs
use rocket::{response::Redirect, routes, uri};
#[allow(unused_variables)]
#[rocket::get("/?<hmac>&<shop>&<timestamp>")]
pub fn install(hmac: &str, shop: &str, timestamp: &str) -> Redirect {
println!("The route matches, that's progress...");
Redirect::to(uri!("this-does-not-exist-yet"))
}
fn rocket() -> rocket::Rocket<rocket::Build> {
rocket::build().mount("/", routes![install])
}
#[rocket::main]
async fn main() {
let _ = rocket().launch().await;
}
Run the server again, try installing again, lets see what we get now…

Huge success! Installing the Shopify app has actually exercised some logic, a redirect to oblivion!

Confirmed by the server – traffic is coming in, a statement is being logged, a response is being issued. Significantly further than where we started, that’s a good stopping point.
One last step before we move on – for clarity’s sake going forward lets move the App URL from "/?<hmac>&<shop>&<timestamp>"
to "/install?<hmac>&<shop>&<timestamp>"
. This will tidy things up very slightly in the future – remember to update your partner dashboard with the new App URL!

Status
Where we started in this post: we had nothing but some Shopify accounts and some incoming web traffic, abandoned at our doorstep and ignored
Where we ended with this post: Installing the Shopify application executes {{logic}} on our local application server and returns a response, though not a very satisfying one
Next post: Implementing the first few steps of Shopify’s OAuth flow