Fast, reliable, productive - Pick three | Rust's slogan
Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.
In this article, you will learn how to deploy a Rust API easily in a few steps. This article is separate into two parts:
- Create a Rust REST API app
- Dockerized our Rust REST API app
- Deploy our Rust REST API app on AWS
Before you begin, this page assumes the following:
- Rust installed on your system (instructions here)
- You have an AWS account
- You have a GitHub account
Let's go!
Create a Rust REST API app
To illustrate the deployment of our Rust API application, we are going to create an API to know if a number is prime number. Let's create our Rust project using cargo
cargo new --bin rust-prime-number-api
Now you must have a rust-prime-number-api
folder with 2 files:
Cargo.toml
src/main.rs
To build our Rust REST API we are going to use Rocket - a web framework for Rust that makes it simple to write fast web application.
Add the rocket
and serde
(JSON serializer/deserializer) dependencies to your Cargo.toml
, then run cargo fetch
(optional) to update your local dependencies.
[package]name = "rust-prime-number-api"version = "0.1.0"edition = "2018"# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html[dependencies]rocket = { version = "0.5.0-rc.1", features = ["json"] }serde = { version = "1.0.130", features = ["derive"] }serde_json = "1.0.68"
Put inside your src/main.rs
the following Rust code
#[macro_use]extern crate rocket;use rocket::serde::json::Json;use serde::Serialize;use std::time::SystemTime;use std::net::{IpAddr, Ipv4Addr};#[derive(Serialize)]struct NumberResponse {number: u64,is_prime_number: bool,execution_time_in_micros: u128}#[get("/")]fn index() -> &'static str {"This is my Rust prime number REST API"}#[get("/isPrime?<number>")]fn get_is_prime(number: u64) -> Json<NumberResponse> {let now = SystemTime::now();Json(NumberResponse {number,is_prime_number: is_prime(number),execution_time_in_micros: now.elapsed().unwrap().as_micros(),})}fn is_prime(n: u64) -> bool {if n <= 1 {return false;}for a in 2..n {if n % a == 0 {return false;}}true}#[rocket::main]async fn main() {let mut config = rocket::config::Config::default();config.address = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));let _ = rocket::build().configure(config).mount("/", routes![index, get_is_prime]).launch().await;}
Run cargo run
and you are supposed to get the following output
🔧 Configured for debug.>> address: 0.0.0.0>> port: 8000>> workers: 16>> ident: Rocket>> keep-alive: 5s>> limits: bytes = 8KiB, data-form = 2MiB, file = 1MiB, form = 32KiB, json = 1MiB, msgpack = 1MiB, string = 8KiB>> tls: disabled>> temp dir: /var/folders/td/bjr48yg96gd2xgd3s44fg40c0000gn/T/>> log level: normal>> cli colors: true>> shutdown: ctrlc = true, force = true, signals = [SIGTERM], grace = 2s, mercy = 3s🛰 Routes:>> (index) GET />> (get_is_prime) GET /isPrime?<number>📡 Fairings:>> Shield (liftoff, response, singleton)🛡️ Shield:>> X-Frame-Options: SAMEORIGIN>> Permissions-Policy: interest-cohort=()>> X-Content-Type-Options: nosniff🚀 Rocket has launched from http://127.0.0.1:8000
You can try your Rust REST API by opening http://127.0.0.1:8000/isPrime?number=9293029022983991
in your browser.
{"number": 9293029022983992,"is_prime_number": false,"execution_time_in_micros": 942894}
Let's now containerized our app with Docker to deploy it on our AWS account.
Dockerized our Rust REST API app
To run our Rust app we need to provide a valid Dockerfile. If you are not familiar with Docker, you can take a look to this article. Here is the content of our Dockerfile.
###################################################################################################### Builder####################################################################################################FROM rust:latest AS builderRUN rustup target add x86_64-unknown-linux-muslRUN apt update && apt install -y musl-tools musl-devRUN update-ca-certificates# Create appuserENV USER=appENV UID=10001RUN adduser \--disabled-password \--gecos "" \--home "/nonexistent" \--shell "/sbin/nologin" \--no-create-home \--uid "${UID}" \"${USER}"WORKDIR /appCOPY ./ .RUN cargo build --target x86_64-unknown-linux-musl --release###################################################################################################### Final image####################################################################################################FROM scratch# Import from builder.COPY --from=builder /etc/passwd /etc/passwdCOPY --from=builder /etc/group /etc/groupWORKDIR /app# Copy our buildCOPY --from=builder /app/target/x86_64-unknown-linux-musl/release/rust-prime-number-api ./# Use an unprivileged user.USER app:appCMD ["/app/rust-prime-number-api"]
Deploy our Rust REST API app on AWS
To deploy our Rust app on AWS we are going to use Qovery. Qovery is the simplest way to deploy any app on AWS. It is the perfect candidate to deploy our Rust REST API in a few steps.
Sign up into Qovery
First, you need to sign up or sign in on Qovery.
- Web
- CLI
Sign in to the Qovery web interface.
Connect your AWS account
To connect your AWS account check out this guide.
Deploy our Rust REST API app
Once your AWS account is set-up, you can deploy your Rust app by..
Creating a project prime number
.
Creating an environment prod
.
Creating an app by selecting your Rust app repository, build mode > Dockerfile, and the port 8000.
And deploy! That's it 🔥... nothing more. Our Rust REST API app is ready
Check out this video to see how I quickly deploy my Rust REST API with Qovery.
Watch this video showing the final result 👇
Wrapping up
Rust combined to Rocket web framework turns building REST API super easy. Deploying your Rust app on AWS with Qovery is as simple as selecting your GitHub repository. Nothing more. Hope you liked it.