Your Rust Web Development Toolset

What to bring on your web journey with Rust

Bastian Gruber

  • Rust developer for the past ~4 years
  • Author of "Rust Web Development"
  • Founder & Co-Organizer "Rust&Tell Berlin"
  • Former Systems Enginner @krakenfx
  • Now Solutions Architect @twilio
  • @recvonline

"Rust Web Development"

  • Pragmatic approach of Web Development in and with Rust
  • "Getting Things Done" mentality with enough theory for further exploration
  • Meant to give out to new hires, or
  • Getting ready for your new Rust job/role
  • rustwebdevelopment.com

Today's talk

  • Understand Rusts web ecosystem
  • What is happening behind the scenes
  • Components of a running web service
  • "How does a web service in Rust look like?"
  • Tools to keep a web service sound and solid
  • Little helpers along the way
Rust ♥ Web
Rust ♥ (?) Web

Rust has no built-in HTTP support (just TCP and lower)

Without HTTP, just TCP streams are handled within the Rust std

                            
                                use std::net::{TcpListener, TcpStream}; 
                                        
                                fn handle_client(stream: TcpStream) { 
                                    // do something 
                                 } 
                                        
                                 fn main() -> std::io::Result<()> { 
                                    let listener = TcpListener::bind("127.0.0.1:80")?; 
                                    for stream in listener.incoming() { 
                                        handle_client(stream?); 
                                    } 
                                    Ok(()) 
                                 }
                            
                          

The previously example was synchronous. How do we make this asynchronous?

That's a lot to take in...

Thank god, 99% of this is hidden behind a framework if you use one!

Example: axum (using tokio for the runtime and hyper for the HTTP server)

  • Logging/tracing: tracing
  • DB access: Diesel (ORM), sqlx (SQL)
  • (De)Serialization of JSON, BSON etc: serde
  • AWS: aws-sdk-rust
  • E-Mail: email
  • Dates/Time: chrono
  • CLI: clap
  • OAuth: oxide-auth

Behind the scenes...

Why is it important to know?

Rust is a low level language - chances are that you might (have to) dig deeper into the stack for a company or project.

Important building blocks: Future, runtime, framework and an HTTP crate

What is a Future?

NodeJS: Promise, Go: goroutines and channels, Rust: Future

A Future is a trait.

                            
pub trait Future {
    type Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll;
}
 
                            
                          
                            
enum Poll {
    Ready(T),
    Pending
}
                        

Implementing it ourselves would look like this:

                            
#[derive(Default)]
struct MyFuture {
    count: u32,
}

impl Future for MyFuture {
    type Output = i32;

    fn poll(&mut self, ctx: &Context) -> Poll {
        match self.count {
            3 => Poll::Ready(3),
            _ => {
                self.count += 1;
                ctx.waker().wake();
                Poll::Pending
            }
        }
    }
}

                            
                        

You actively have to "poll" (.await) on a Future to start it/make progress on it.

To do so, the runtime comes into the picture.

Runtime + Kernel

A web framework comes with a HTTP crate (protocol + server implementation).

Popular frameworks are: actix, warp, rocket and axum.

In code (with warp):

                            
use warp::Filter;

#[tokio::main]
async fn main() {
    // GET /hello/warp => 200 OK with body "Hello, warp!"
    let hello = warp::path!("hello" / String)
        .map(|name| format!("Hello, {}!", name));

    warp::serve(hello)
        .run(([127, 0, 0, 1], 3030))
        .await;
}
                            
                        

How does a web service in Rust look like?

Example from the book

Tools to keep a web service sound and solid
Comments and Doc-Comments
cargo doc --open
Linting (Clippy)
rustup component add clippy
cargo clippy
 warning: length comparison to zero 

  --> src/routes/question.rs:12:6 

   | 
12 |   if params.len() > 0 { 
   |      ^^^^^^^^^^^^^^^^ help: using `!is_empty` is 
            clearer and more explicit: `!params.is_empty()` 

 
cargo clippy --fix
Rust formatter: rustfmt
rustup component add rustfmt
cargo fmt
Testing: Built-in
Logging,tracing and debugging: Read the book ;)
For async web services, tracing is the recommended crate.
Little helpers along the way
Rust Playground
Exercism
transform
rustwebdevelopment.com