Skip to content

Latest commit

 

History

History

4_2_http

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Step 4.2: HTTP servers and clients

Estimated time: 1 day

The current situation regarding HTTP in Rust ecosystem can be grasped quite well in the "Web programming" section of "Awesome Rust" and in the "Web Frameworks", "HTTP Clients" and "Lower Web-Stack" topics of "Are we web yet?". Of course, most of them use async I/O.

Low-level

There are few core crates, providing general-purpose HTTP implementation, powering the whole variety of web frameworks and HTTP clients in Rust ecosystem.

The most prominent and mature one is, of course, the hyper crate (built using tokio). Almost all web frameworks of Rust ecosystem are built on top of it.

The main alternatives are:

For more details, read through the following articles:

Server

While hyper provides its own server implementation, using it directly can feel quite low-level and unergonomic, due to its nature. Naturally, there are numerous web frameworks built on top of hyper, which provide high-level, ergonomic and friendly interface. The most notable are:

  • axum - a web application framework that focuses on ergonomics and modularity, and provides macro-free request routing (yet ergonomic and declarative), simple and predictive error-handling, and leverages full advantage of the tower and tower-http ecosystem of middleware, services, and utilities.
  • warp - a super-easy, composable, web server framework for warp speeds, built around the "everything is a Filter" concept.
  • rocket - a web framework, aims to be fast, easy, and flexible while offering guaranteed safety and security where it can, and, importantly, aiming to be fun (accomplishing this by ensuring that you write as little code as needed to accomplish your task).
  • poem - a full-featured and easy-to-use web framework, focusing on providing all the capabilities (like i18n) out-of-the-box.
  • salvo - a powerful and simple web server framework, adopting HTTP/3 implementation.

For those who prefer async-std ecosystem, the definitive choice (and the single one, at the moment) is the tide crate.

All the web frameworks above inherit the work-stealing from the asynchronous runtime they're run on, and so, require the proper synchronization (being Send) from user-provided HTTP request handlers, which may introduce an unnecessary or undesired overhead. That's why actix-web crate was designed and implemented specifically with this consideration in mind (to avoid work-stealing), being built on top of actix-rt crate (leveraging thread-per-core model), and thus, not requiring any synchronization in its request handlers (allowing !Send Futures). Also, actix-web, at the time, was the first mature and production-ready web framework in Rust ecosystem, possessing a top of "TechEmpower Web Framework Benchmarks".

For better understanding and familiarity with HTTP servers in Rust, read through the following articles:

Client

Similarly to a server, while hyper provides its own client implementation, using it directly can feel quite low-level and unergonomic. So, the "default choice" HTTP client (and mostly used) in Rust ecosystem is the reqwest crate, built on top of hyper.

isahc crate, as an alternative, is a runtime-agnostic wrapper (with major focus on being practical and ergonomic) around the famous cURL library.

For simple and trivial scenarios, where an asynchronous runtime is redundant and/or low overhead is preferred, the viable alternative is the ureq crate.

For async-std ecosystem, the main crate is surf, which is, however, not restricted to async-std only, and is able to use alternative backends: cURL (via isahc), hyper, WASM (via browser's window.fetch API).

For actix-web ecosystem, the meaningful option would be the awc crate, which supports WebSocket connections out-of-the-box (while most other HTTP clients lacks that).

For better understanding and familiarity with HTTP clients in Rust, read through the following articles:

WebSocket

Many HTTP clients and servers in Rust lack a built-in WebSocket implementation. Therefore, the tungstenite crate was created, providing a barebone and agnostic WebSocket implementation. Crates, like async-tungstenite and tokio-tungstenite, provide the actual ready-for-use client/server implementation for the desired ecosystem and asynchronous runtime.

For actix-web ecosystem, the idiomatic solution is the actix-web-actors::ws module, providing implementation in a form of actor (via actix).

For better understanding and familiarity with WebSocket implementations in Rust, read through the following articles:

Task

Rework the task from the previous step in a client-server architecture. It should consist of a CLI client and a server daemon, and utilize the "thin client" approach:

  • CLI client does nothing except sending commands "as is" to the server and rendering its responses.
  • Server daemon, having a single HTTP endpoint, does all the parsing and executing of commands sent by the CLI client.

Questions

After completing everything above, you should be able to answer (and understand why) the following questions:

  • What is HTTP? What does HTTP/2 imply? What does HTTP/3 imply?
  • How do work-stealing and thread-per-core paradigms affect programming a web server in practice? Which one is better and when? When does this question (choosing) become meaningful, in practice?
  • What are common crates for making HTTP requests in Rust? Which trade-offs do they have?
  • What is WebSocket? How is it used and when? How does it work, in a nutshell?