# Rocket v0.5: Stable, Async, Sentinels, Figment, Shield, Streams, SSE, WebSockets, & More!
Posted by Sergio Benitez on May 26, 2023
Four years, almost a thousand commits, and over a thousand issues, discussions,
and PRs later, I am ~~relieved~~ thrilled to announce the general availability
of Rocket v0.5.
> **Rocket** is a backend web framework for Rust with a focus on usability,
> security, extensibility, and speed. Rocket makes it simple to write secure web
> applications without sacrificing usability or performance.
We encourage all users to upgrade. For a guided upgrade from Rocket v0.4 to
Rocket v0.5, please consult the newly available [upgrading guide]. Rocket v0.4
will continue to be supported and receive security updates until the next major
release.
[upgrading guide]: ../../guide/upgrading
## What's New?
Almost every aspect has been reevaluated with a focus on usability, security,
and consistency across the library and [broader ecosystem]. The changes are
numerous, so we focus on the most impactful changes here and encourage everyone
to read the [CHANGELOG] for a complete list. For answers to frequently asked
questions, see the new [FAQ].
[broader ecosystem]: ../../guide/faq/#releases
[CHANGELOG]: https://github.com/SergioBenitez/Rocket/blob/v0.5.0/CHANGELOG.md
[FAQ]: ../../guide/faq
### ⚓ Support for Stable `rustc`
Rocket v0.5 compiles and builds on Rust stable with an entirely asynchronous
core. This means that you can compile Rocket application with `rustc` from the
stable release channel.
Using the stable release channel ensures that _no_ breakages will occur when
upgrading your Rust compiler or Rocket. That being said, Rocket continues to
take advantage of features only present in the nightly channel.
### 📥 Async I/O
The new asynchronous core requires an async runtime to run. The new
[`launch`] and [`main`] attributes simplify starting a runtime suitable for
running Rocket applications. You should use [`launch`] whenever possible.
Additionally, the `rocket::ignite()` function has been renamed to
[`rocket::build()`]; calls to the function or method should be replaced
accordingly. Together, these two changes result in the following diff to what
was previously the `main` function:
```diff
- fn main() {
- rocket::ignite().mount("/hello", routes![hello]).launch();
- }
+ #[launch]
+ fn rocket() -> _ {
+ rocket::build().mount("/hello", routes![hello])
+ }
```
### 💂 Sentinels
Rocket v0.5 introduces [sentinels]. Entirely unique to Rocket, sentinels offer
an automatic last line of defense against runtime errors by enabling any type
that appears in a route to abort application launch if invalid conditions are
detected. For example, the [`&State`] guard in v0.5 is a [`Sentinel`] that
aborts launch if the type `T` is not in managed state, thus preventing
associated runtime errors.
You should consider implementing `Sentinel` for your types if you have guards
(request, data, form, etc.) or responders that depend on `Rocket` state to
function properly. For example, consider a `MyResponder` that expects:
* An error catcher to be registered for the `400` status code.
* A specific type `T` to be in managed state.
Making `MyResponder` a sentinel that guards against these conditions is as
simple as:
```rust
use rocket::{Rocket, Ignite, Sentinel};
# struct MyResponder;
# struct T;
impl Sentinel for MyResponder {
fn abort(r: &Rocket) -> bool {
!r.catchers().any(|c| c.code == Some(400)) || r.state::().is_none()
}
}
```
[sentinels]: @api/rocket/trait.Sentinel.html
[`Sentinel`]: @api/rocket/trait.Sentinel.html
[`&State`]: @api/rocket/struct.State.html
### 🛡️ Shield
### 🌊 Streams and SSE
Rocket v0.5 introduces real-time, typed, `async` [streams]. The new [async
streams] section of the guide contains further details, and we encourage all
interested parties to see the new real-time, multi-room [chat example].
As a taste of what's possible, the following `stream` route emits a `"ping"`
Server-Sent Event every `n` seconds, defaulting to `1`:
```rust
# use rocket::*;
use rocket::response::stream::{Event, EventStream};;
use rocket::tokio::time::{interval, Duration};
#[get("/ping?")]
fn stream(n: Option) -> EventStream![] {
EventStream! {
let mut timer = interval(Duration::from_secs(n.unwrap_or(1)));
loop {
yield Event::data("ping");
timer.tick().await;
}
}
}
```
[streams]: @api/rocket/response/stream/index.html
[async streams]: @guide/responses/#async-streams
[chat example]: @example/chat
### 🔌 WebSockets
Rocket v0.5 introduces support for HTTP connection upgrades via a new [upgrade
API]. The API allows responders to take over an HTTP connection and perform raw
I/O with the client. In other words, an HTTP connection can be _upgraded_ to any
protocol, including HTTP WebSockets!
The newly introduced [`rocket_ws`] library takes advantage of the new API to
implement first-class support for WebSockets entirely outside of Rocket's core.
The simplest use of the library, implementing an echo server and showcasing that
the incoming message stream is `async`, looks like this:
```rust
# use rocket::get;
# use rocket_ws as ws;
#[get("/echo")]
fn echo_compose(ws: ws::WebSocket) -> ws::Stream!['static] {
ws.stream(|io| io)
}
```
The simplified [async streams] generator syntax can also be used:
```rust
# use rocket::get;
# use rocket_ws as ws;
#[get("/echo")]
fn echo_stream(ws: ws::WebSocket) -> ws::Stream!['static] {
ws::Stream! { ws =>
for await message in ws {
yield message?;
}
}
}
```
For complete usage details, see the [`rocket_ws`] documentation.
[upgrade API]: @api/rocket/response/struct.Response.html#upgrading
[`rocket_ws`]: @api/rocket_ws
[GitHub issue tracker]: https://github.com/SergioBenitez/Rocket/issues
[GitHub discussions]: https://github.com/SergioBenitez/Rocket/discussions
[migration guide]: ../../guide/upgrading
[CHANGELOG]: https://github.com/SergioBenitez/Rocket/blob/v0.5-rc/CHANGELOG.md#version-050-rc2-may-9-2022
## Thank You
- Aaron Leopold
- Abdullah Alyan
- Aditya
- Alex Macleod
- Alex Sears
- Alexander van Ratingen
- ami-GS
- Antoine Martin
- arctic-alpaca
- arlecchino
- Arthur Woimbée
- atouchet
- Aurora
- badoken
- Beep LIN
- Ben Sully
- Benedikt Weber
- BlackDex
- Bonex
- Brenden Matthews
- Brendon Federko
- Brett Buford
- Cedric Hutchings
- Cezar Halmagean
- Charles-Axel Dein
- Compro Prasad
- Daniel Wiesenberg
- David Venhoek
- Dimitri Sabadie
- Dinu Blanovschi
- Dominik Boehi
- Doni Rubiagatra
- Edgar Onghena
- Edwin Svensson
- est31
- Felix Suominen
- Filip Gospodinov
- Flying-Toast
- Follpvosten
- Francois Stephany
- Gabriel Fontes
- gcarq
- George Cheng
- Giles Cope
- Gonçalo Ribeiro
- hiyoko3m
- Howard Su
- hpodhaisky
- Ian Jackson
- IFcoltransG
- Indosaram
- inyourface34456
- J. Cohen
- Jacob Pratt
- Jacob Sharf
- Jacob Simpson
- Jakub Dąbek
- Jakub Wieczorek
- James Tai
- Jason Hinch
- Jeb Rosen
- Jeremy Kaplan
- Joakim Soderlund
- Johannes Liebermann
- John-John Tedro
- Jonah Brüchert
- Jonas Møller
- Jonathan Dickinson
- Jonty
- Joscha
- Joshua Nitschke
- JR Heard
- Juhasz Sandor
- Julian Büttner
- Juraj Fiala
- Kenneth Allen
- Kevin Wang
- Kian-Meng Ang
- Konrad Borowski
- Leonora Tindall
- lewis
- Lionel G
- Lucille Blumire
- Mai-Lapyst
- Manuel
- Marc Schreiber
- Marc-Stefan Cassola
- Marshall Bowers
- Martin1887
- Martinez
- Matthew Pomes
- Maxime Guerreiro
- meltinglava
- Michael Howell
- Mikail Bagishov
- mixio
- multisn8
- Necmettin Karakaya
- Ning Sun
- Nya
- Paolo Barbolini
- Paul Smith
- Paul van Tilburg
- Paul Weaver
- pennae
- Petr Portnov
- philipp
- Pieter Frenssen
- PROgrm_JARvis
- Razican
- Redrield
- Rémi Lauzier
- Riley Patterson
- Rodolphe Bréard
- Roger Mo
- RotesWasser
- rotoclone
- Rudi Floren
- Samuele Esposito
- Scott McMurray
- Sergio Benitez
- Silas Sewell
- Soham Roy
- Stuart Hinson
- Thibaud Martinez
- Thomas Eckert
- ThouCheese
- Tilen Pintarič
- timando
- timokoesters
- toshokan
- TotalKrill
- Vasili
- Vladimir Ignatev
- Wesley Norris
- xelivous
- YetAnotherMinion
- Yohannes Kifle
- Yusuke Kominami
## What's Next?