Building a web site in Rust
rust, cargo, axum, and tokio
![Erik](/images/avatar.png)
![Cover Image for Building a web site in Rust](/images/stopwatch.jpg)
Introduction
Today, we will be building:
- A simple web server using Rust
- A simple website served from this web server
- An improved version of this website using web components
We will start by setting up a new Rust project using Cargo, the Rust package manager, and then build a simple web server using Axum. Once the web server is working as we expect, we'll extend this to make a simple set of web components to serve a user-driven application.
Getting Started with Rust
Rust is a systems programming language that focuses on performance, safety, and concurrency. It is designed to be fast, reliable, and secure, making it an excellent choice for building web applications at scale. Before we dive into building a web server, let's start by setting up the Rust toolchain and creating a new project using Cargo.
Installation and Setup
The first step to getting started with Rust is to install the Rust toolchain. You can install Rust using the official installer available at rustup.rs. Rustup is a toolchain installer for Rust that makes it easy to install and manage multiple versions of Rust on your system.
Once you have installed Rust, you can verify the installation by running the following command in your terminal:
rustc --version
This command should print the installed version of Rust on your system. If you see the version number, then Rust has been installed successfully.
At the time of this post, my installed version is
rustc 1.76.0
Create a New Project Using Cargo
Cargo is Rust's package manager and build system. It makes it easy to manage Rust projects, including building, testing, and packaging. Cargo also handles dependencies, making it easy to add external libraries to your project. To create a new Rust project, you can use the cargo new
command:
cargo new my-web-server
This command will create a new directory called my-web-server
with a basic Rust project structure. Inside the my-web-server
directory, you will find the following files:
Cargo.toml
: The manifest file that describes the project and its dependencies.src/main.rs
: The main entry point for the Rust application.
Building the Server
Before we can get building the server, we need to install some basic dependencies. We will be using the axum
and tokio
libraries to build our web server. We can add these dependencies to the Cargo.toml
file.
Add Axum and Tokio Dependencies
Run the following command to add the axum
and tokio
dependencies to the Cargo.toml
file:
cargo add axum
cargo add tokio --features full
After this completes, your Cargo.toml
file should look something like this:
[package]
name = "my-web-server"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
axum = "0.7.4"
tokio = { version = "1", features = ["full"] }
Axum
Axum is a web framework built on top of hyper
, a fast low-level HTTP implementation for Rust. Axum provides a powerful and ergonomic API for building asynchronous web applications. It is designed to be composable, allowing you to build complex applications by combining smaller, reusable components.
Axum uses Rust's async/await syntax to handle asynchronous operations, making it easy to write efficient and scalable web applications. It also provides a rich set of features, including routing, middleware, error handling, and more. Axum uses tokio as its asynchronous runtime, making it a great choice for building high-performance web applications.
Tokio
Tokio is an asynchronous runtime for Rust that provides a set of tools for building asynchronous applications. It includes an event loop, task scheduler, and other miscellaneous utilities for working with asynchronous I/O.
Define our Entry Point
The src/main.rs
file is the main entry point for the Rust application. Open the src/main.rs
file in a text editor and add a function to run the web server:
use axum::{
routing::get,
Router,
};
#[tokio::main]
async fn main() {
// build our application with a single route
let app = Router::new().route("/", get(|| async { "Hello, World!" }));
// run our app with hyper, listening globally on port 3000
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
In this example, we are creating a simple web server that responds with "Hello, World!" for GET /
. We are using the axum
and tokio
dependencies to define the web server and run it asynchronously.
Run the Web Server
To run the web server, use the following command:
cargo run
Let's see how we did. Run the following curl
command to test the server:
curl http://localhost:3000/
> Hello World!
Great, it looks like our server is working! We now have an HTTP handler responding to requests.
Awesome! Now, let's make our website a bit more interesting. We'll start by adding a simple HTML page to our server, enhancing the response with a bit of CSS and JavaScript as we go.
Building the Website
Let's start by adding a basic web page to our server.