Thanks for reading! I like making interactive visualisations for my programming blog. Sometimes I do projects too. Oh, and before you go, sign the guestbook! See you around! —Lean
At the company I work for, there is something called a “professional education leave”, which lets me take a day off to learn something new or attend conferences or whatever professional education means. I took the opportunity to learn the Rust programming language.
I didn’t want to follow tutorials, so I thought of a project to learn with, which ended up being “make a single-file website web server”. It was inspired by the article my website is one binary by j3s.
fn main() {
println!("Hello World!");
}
My first impression was that it is a mature programming language that is crazy about compile-time stuff. For example, the above println!
call is a macro, which expands to something more verbose… Apparently, with macros you can also make full-blown DSLs that are directly embedded in Rust code.
The rustc
compiler’s error messages were very good.
I think I haven’t really dived deep enough to discover the standout features that I keep hearing about like memory management safety. So unfortunately I didn’t get the hype at this time.
The standard Rust library provides a TCP module, but no HTTP one. So it’s a level lower than NodeJS, which is understandable.
I didn’t want to implement the HTTP protocol, so I searched for an HTTP library.
I found rouille, a web micro-framework. I installed it via cargo
which is like npm
but for Rust.
It was really easy to get it set up and running.
For starters, I made two pages: /
and /about
.
// main.rs
use rouille::Response;
use rouille::router;
mod pages {
pub mod index;
pub mod about;
}
fn main() {
rouille::start_server("0.0.0.0:8080", move |request| {
let response = router!(request,
(GET) (/) => {
pages::index::page(request)
},
(GET) (/about) => {
pages::about::page(request)
},
_ => Response::empty_404()
);
return response;
});
}
Notice the router!
macro! Apparently it allows me to write GET
and the routes /
and /about
plainly into code. Those aren’t strings! Nor are they Rust keywords! It’s macro magic. It’s even more magical than Kotlin’s lambdas. I think this is a powerful but dangerous tool which could make learning Rust codebases harder. I like it though. Instead of parsing these routes at runtime, errors can be caught at compile time.
One little snag was that Rust’s module system was a little confusing, coming from ES6 where everything is explicit.
In Rust, modules map to files. Module naming and hierarchy follows the filesystem structure.
I didn’t fully understand modules properly but it seems that I can use the mod
keyword to import modules. And that was enough knowledge to proceed with the project.
In the above code I separated the code that renders the pages into separate files in pages/index.rs
and pages/about.rs
. To import them in the main file, I had this declaration at the top:
mod pages {
pub mod index;
pub mod about;
}
As I defined a top-level page()
function in each of these files, calling them from the main file would be something like this: pages::index::page(request)
.
The top-level page
functions simply return static HTML Response
s for now.
Here’s one that handles the root /
route:
// pages/index.rs
use rouille::Request;
use rouille::Response;
pub fn page(_request: &Request) -> Response {
return Response::html(r#"<!doctype html>
<title>Tiny site</title>
<h1>Hello, world!</h1>
<p>Welcome to my tiny site!</p>
<a href="/about">About</a>
"#);
}
Which renders this page:
To avoid repetitively escaping double quotes in HTML, I used the raw string literal which looks r#"something like this"#
to write the HTML response in Rust.
I haven’t done this, but I imagine components or “includes” can be implemented by simply calling component functions normally and concatenating the resulting HTML fragments together. Nothing fancy required, for a tiny website.
I wonder if there are templating systems that take advantage of Rust’s compile-time macros. A quick search revealed a lot of them. In fact, that seems to be the “Rust way” of doing HTML templates. One example is Maud:
html! {
article data-index="12345" {
h1 { "My blog" }
tag-cloud { "pinkie pie pony cute" }
}
}
That looks a lot like Jetpack Compose in Kotlin. Seems like fun way to write HTML. I fear I might be taken by a strange mood and convert my entire website into Rust. I guess paid hosting for non-static sites would be a good deterrent.
That was a nice dip into Rust. I’m still interested in the hyped-up features like memory management but I guess an HTML web server wouldn’t need much of those things after all. Maybe the next Rust learning exercise would be something like a small video game. Now that’s something that would require memory management and algorithms.
Here’s the repo for my tiny web server in Rust: github.com/Kalabasa/tala.
Thanks for reading! I like making interactive visualisations for my programming blog. Sometimes I do projects too. Oh, and before you go, sign the guestbook! See you around! —Lean