Rust Website Example: Building a Simple Website with Rust and Axum
Rust is a systems programming language known for its speed, safety, and modern tooling. It has gained popularity for web development due to frameworks like Axum, Rocket, and Actix-web, which simplify building scalable and efficient web applications. This article provides a step-by-step guide to creating a basic website using Rust and Axum.
Why Use Rust for Web Development?
- Performance: Rust compiles to machine code, ensuring fast execution.
- Memory Safety: Rust prevents common bugs like null pointer dereferences.
- Concurrency: Built-in support for asynchronous programming.
- Growing Ecosystem: Modern frameworks and libraries for web applications.
Setting Up a Rust Website
Step 1: Create a New Rust Project
Run the following command to create a new project:
cargo new rust_website
cd rust_website
This will create a new directory with the following structure:
rust_website/
├── Cargo.toml
└── src/
└── main.rs
Step 2: Add Dependencies
Add the following dependencies to your Cargo.toml
file:
[dependencies]
axum = "0.6"
tokio = { version = "1.0", features = ["full"] }
tower = "0.4"
hyper = "0.14"
serde = { version = "1.0", features = ["derive"] }
These dependencies include:
- Axum: Web framework for Rust.
- Tokio: Async runtime for Rust.
- Tower: Middleware and utilities.
- Hyper: HTTP server and client library.
- Serde: Serialization library for JSON handling.
Run cargo build
to download and compile the dependencies.
Step 3: Write the Website Code
Replace the content of src/main.rs
with the following code:
use axum::{
routing::{get, post},
Router,
Json,
};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[tokio::main]
async fn main() {
// Build the Axum application
let app = Router::new()
.route("/", get(homepage))
.route("/about", get(about))
.route("/contact", post(contact));
// Define the address for the server
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("Server running at http://{}", addr);
// Run the Axum server
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
// Homepage handler
async fn homepage() -> &'static str {
"Welcome to My Rust Website!"
}
// About page handler
async fn about() -> &'static str {
"This is the About Page of the Rust Website."
}
// Contact form handler
#[derive(Deserialize)]
struct ContactForm {
name: String,
message: String,
}
#[derive(Serialize)]
struct ResponseMessage {
status: String,
message: String,
}
async fn contact(Json(payload): Json<ContactForm>) -> Json<ResponseMessage> {
Json(ResponseMessage {
status: "success".to_string(),
message: format!("Thanks for reaching out, {}!", payload.name),
})
}
Step 4: Run the Server
Start the server by running:
cargo run
You should see output like this:
Server running at http://127.0.0.1:3000
How the Code Works
- Homepage:
- The
homepage
handler responds with a simple text message. - Access it via
http://127.0.0.1:3000/
.
- The
- About Page:
- The
about
handler provides information about the site. - Access it via
http://127.0.0.1:3000/about
.
- The
- Contact Form:
- The
contact
handler processes JSON payloads for contact form submissions.
- The
Response:
{
"status": "success",
"message": "Thanks for reaching out, Alice!"
}
Example POST request:
curl -X POST http://127.0.0.1:3000/contact \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "message": "Hello from Rust!"}'
Testing the Website
1. Access Pages
- Open a browser and visit:
- Homepage:
http://127.0.0.1:3000/
- About Page:
http://127.0.0.1:3000/about
- Homepage:
2. Submit Data
Use tools like Postman or curl
to test the /contact
endpoint.
Adding HTML Templates (Optional)
To serve HTML pages instead of plain text, you can integrate a template engine like Tera.
Update Cargo.toml
:
tera = "1.12"
Serve HTML Template:
use axum::{
response::Html,
routing::get,
Router,
};
use tera::{Context, Tera};
async fn homepage() -> Html<String> {
let tera = Tera::new("templates/**/*.html").unwrap();
let mut context = Context::new();
context.insert("title", "Rust Website");
context.insert("message", "Welcome to My Rust Website!");
Html(tera.render("homepage.html", &context).unwrap())
}
Create a templates/homepage.html
file:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>{{ message }}</h1>
</body>
</html>
Best Practices for Rust Websites
- Use Middleware:
- Add logging, authentication, or rate-limiting middleware using Tower.
- Secure with HTTPS:
- Use
hyper-rustls
to enable HTTPS.
- Use
- Optimize Performance:
- Leverage Rust’s async capabilities to handle concurrent requests efficiently.
- Testing:
- Use
cargo test
to write unit and integration tests for your handlers.
- Use
Conclusion
Building a website with Rust and Axum is straightforward, thanks to its modern async ecosystem and ergonomic APIs. Whether you’re creating a simple website or a complex web application, Rust offers performance, reliability, and scalability. Start with the example above and expand it to include features like templates, databases, and authentication to build a full-featured web application.