How to Set Up a Basic Axum Project: A Step-by-Step Guide
If you’ve been exploring Rust and want to build web applications, Axum is a great framework to get started with. It’s built on top of Tokio and Hyper, offering a high-performance, type-safe way to create web services. In this article, we’ll walk through setting up a basic Axum project from scratch and build a simple web server together.
This guide is designed for developers who want to dive in and start coding right away. By the end, you’ll have a solid foundation to explore Axum further and build more complex applications.
Step 1: Setting Up Your Project
Before we get our hands dirty with code, let’s make sure everything is ready. Open your terminal and run the following command to create a new Rust project:
cargo new axum_hello_world --bin
cd axum_hello_world
This creates a new directory named axum_hello_world
and initializes it as a binary crate. Now, let’s add Axum as a dependency.
Open the Cargo.toml
file and add Axum under the [dependencies]
section:
[dependencies]
axum = "0.6"
tokio = { version = "1", features = ["full"] }
- Axum will provide the framework for the web server.
- Tokio is a runtime for asynchronous tasks, which is a fundamental part of Axum.
Step 2: Writing the First Route
Let’s write our first Axum endpoint. Open src/main.rs
and replace the existing code with this:
use axum::{Router, routing::get};
use std::net::SocketAddr;
#[tokio::main]
async fn main() {
// Create a new router and add a simple route
let app = Router::new().route("/", get(|| async { "Hello, World!" }));
// Set the address for the server to listen on
let addr: SocketAddr = "127.0.0.1:3000".parse().unwrap();
// Start the server
println!("Server running on http://{}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
Breakdown:
- Imports: We import
Router
andget
from Axum. Theget
function allows us to define a simple GET route. We also bring inSocketAddr
fromstd::net
to specify where the server should listen. #[tokio::main]
: This macro sets up the asynchronous runtime, which is required for handling web requests. It turns ourmain
function into an async function.- Router Setup: We create a new
Router
and define a single route (/
) that responds with"Hello, World!"
when accessed via a GET request. - Server Binding: We specify the server address (localhost on port 3000) and tell Axum to start the server.
Step 3: Running the Server
Now that the code is written, let’s run the server. In your terminal, execute:
cargo run
You should see something like this in the terminal:
Server running on http://127.0.0.1:3000
To test the server, open your browser or use curl
to visit http://127.0.0.1:3000
. You should see:
Hello, World!
What just happened?
We set up a basic web server using Axum. The server listens on port 3000 and serves a "Hello, World!" message when accessed via a GET request. This is the simplest possible setup for an Axum application.
Step 4: Handling Parameters
Now let’s introduce some dynamic behavior. Let’s modify our route to accept a name parameter in the URL and say hello to the person by name. Update your code like this:
use axum::{Router, routing::get, extract::Path};
use std::net::SocketAddr;
async fn hello(Path(name): Path<String>) -> String {
format!("Hello, {}!", name)
}
#[tokio::main]
async fn main() {
// Create a new router and add a route that accepts a name parameter
let app = Router::new().route("/hello/:name", get(hello));
// Set the address for the server to listen on
let addr: SocketAddr = "127.0.0.1:3000".parse().unwrap();
// Start the server
println!("Server running on http://{}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
What’s new here?
- Extracting Parameters: We use
Path
to extract thename
parameter from the URL. In this case, the URL/hello/:name
will capture whatever comes after/hello/
and pass it to thehello
function. - Dynamic Response: The
hello
function takes thename
and returns a personalized greeting usingformat!
.
Step 5: Testing the New Route
With the new code in place, run the server again using cargo run
. Now, try visiting http://127.0.0.1:3000/hello/Alice
in your browser (or use curl
). You should see:
Hello, Alice!
Change the Alice
part of the URL to any name you like, and the server will respond with a customized greeting.
Step 6: Challenge – Add Another Route!
Here’s a quick challenge for you: Add another route that accepts a number and returns the square of that number. You can use a route like /square/:num
and extract the number from the URL. Think about how you’d process the number and send back the result.
Try it out and see how it works!
Hint:
You’ll need to use Path
to extract the number and convert it to an integer using str::parse
. Then, return the square of the number.
Recap and Conclusion
Congratulations! You’ve just built a basic web server with Axum. Here's a summary of what we covered:
- Setting Up the Project: We created a new Rust project and added Axum as a dependency.
- Writing Your First Route: We set up a simple route that responds with "Hello, World!".
- Handling Parameters: We created a dynamic route that greets users by their name.
- Challenge: We introduced a small challenge to get you thinking about handling other types of data, like numbers.
Axum is a powerful framework, and this simple example just scratches the surface. Now that you have the basics, you can dive deeper into Axum’s features like middleware, error handling, and more complex routing.
For more learning, check out the official Axum documentation and explore more advanced features. Keep experimenting and building – happy coding!