23 KiB
FAQ
Below you'll find a collection of commonly asked questions and answers. If you have suggestions for questions you'd like to see answered here, comment on the discussion thread.
About Rocket
Is Rocket a monolithic framework like Rails? Or is it more like Flask? #
Neither!
Rocket's core is small yet complete when it comes to security and correctness. It mainly consists of:
- Guard traits like
FromRequest
andFromData
. - Derive macros for all commonly used traits.
- Attribute macros for routing.
- Thorough compile and launch-time checking.
- Optional features to enable functionality like TLS, secrets, and so on.
- Zero-copy parsers and validators for common formats like multipart and SSE.
- Syntax sugar extensions for features like async streams and traits.
The goal is for functionality like templating, sessions, ORMs, and so on to be
implemented entirely outside of Rocket and yet feel first-class. Indeed, crates
like rocket_dyn_templates
and rocket_db_pools
do just this.
As a result, Rocket is neither "bare-bones" nor is it a kitchen sink for all possible features. Unlike other frameworks in the Rust ecosystem, Rocket makes it its mission to help you avoid security and correctness blunders out-of-the-box. It does this by including, out-of-the-box:
- A flexible, type-based configuration system.
- Security and privacy headers by default.
- Zero-Copy RFC compliant URI parsers.
- Safe, typed URIs with compile-time checking.
- Thorough compile-time and launch-time checking of routes.
- A complete testing framework with sync and
async
variants. - Safe, exclusive access to fully decoded HTTP values.
- Mandatory data limits to prevent trivial DoS attacks.
Of course, this functionality comes at a compile-time cost (but notably, not at a runtime cost), impacting Rocket's clean build-time. For comparison, here's what building "Hello, world!" for the first time in popular Rust web frameworks looks like:
Framework | Dependencies | Build Time |
---|---|---|
Rocket 0.5-rc.2 | 148 | 44s |
Actix-Web 4.0-beta.8 | 175 | 47s |
Tide 0.16 | 209 | 34s |
Warp 0.3 | 148 | 37s |
· Measurements taken on a MacBookPro15,1 Intel Core i9 @ 2.9GHZ, macOS
11.2.1, Rust 1.53 stable. Best of 3.
· Rocket includes features like multipart parsing and static file
serving that would require additional deps in other frameworks.
Of course, iterative build-time is nearly identical for all frameworks, and the
time can be further reduced by using faster linkers like lld
. We think the
trade-off is worth it. Rocket will never compromise security, correctness, or
usability to "win" at benchmarks of any sort.
I want a small and compact web framework. Is Rocket it? #
We think so! See "Is Rocket a monolithic framework like Rails?"
I want a web framework with all the bells and whistles. Is Rocket it? #
We think so! See "Is Rocket a monolithic framework like Rails?"
Can I use Rocket in production? Should I? It's only v0.x! #
We enthusiastically recommend using Rocket in production, with the following caveats:
-
Run Rocket behind a reverse proxy like HAProxy or in a production load balancing environment. Rocket (Hyper) doesn't employ any defenses against DDoS attacks or certain DoS attacks.
-
Use a TLS termination proxy for zero-downtown certificate rotation.
-
Properly configure your databases and database pools, especially with respect to the pool size.
-
Ensure no blocking I/O happens outside of
spawn_blocking()
invocations.
While Rocket is still in the 0.x
phase, the version number is purely a
stylistic choice. In fact, we consider Rocket to be the most mature web
framework in the Rust ecosystem. To our knowledge, Rocket is the only Rust web
framework that correctly implements:
- Server-Sent Events
- Graceful Shutdown
- Form Parsing with Arbitrarily Structure
- Zero-Copy, RFC Conforming URI Types
- Ambiguity-Free Routing
- Streamed Multipart Uploads
If you're coming from a different ecosystem, you should feel comfortable
considering Rocket's v0.x
as someone else's vx.0
. Rust and Cargo's semver
policy, and Rocket's strict adherence to it, ensures that Rocket will never
break your application when upgrading from 0.x.y
to 0.x.z
, where z >= y
.
Furthermore, we backport all security and correctness patches to the previous
major release (0.{x-1}.y
), so your application remains secure if you need time
to upgrade.
Is Rocket slow? Is Rocket fast? #
Rocket is pretty fast.
A commonly repeated myth is that Rocket's great usability comes at the cost of runtime performance. This is false. Rocket's usability derives largely from compile-time checks with zero bearing on runtime performance.
So what about benchmarks? Well, benchmarking is hard, and besides often being conducted incorrectly, often appear to say more than they do. So, when you see a benchmark for "Hello, world!", you should know that the benchmark's relevance doesn't extend far beyond "Hello, world!" servers and the specific way the measurement was taken. In other words, they provide only a baseline truth that is hard to extrapolate to real-world use-cases, your use-case.
Nevertheless, here are some things you can consider as generally true about Rocket applications:
- They'll perform much, much better than those written in scripting languages like Python or Ruby.
- They'll perform much better than those written in VM or JIT languages like JavaScript or Java.
- They'll perform a bit better than those written in compiled but GC'd languages like Go.
- They'll perform competitively with those written in compiled, non-GC'd languages like Rust or C.
Again, we emphasize generally true. It is trivial to write a Rocket application that is slower than a similar Python application.
Besides a framework's internal performance, you should also consider whether it enables your application itself to perform well. Rocket takes great care to enable your application to perform as little work as possible through unique-to-Rocket features like managed state, request-local state, and zero-copy parsing and deserialization.
What are some examples of "big" apps written in Rocket? #
Here are some notable projects and websites in Rocket we're aware of:
- Vaultwarden - A BitWarden Server
- Conduit - A Matrix Homeserver
- Rust-Lang.org - Rust Language Website
- Plume - Federated Blogging Engine
- Hagrid - OpenPGP KeyServer (keys.openpgp.org)
- SourceGraph Syntax Highlighter - Syntax Highlighting API
Let us know if you have a notable, public facing application written in Rocket you'd like to see here!
When will version `$y` be released? Why does it take so long? #
Rocket represents an ecosystem-wide effort to create a web framework that enables writing web applications with unparalleled security, performance, and usability. From design to implementation to documentation, Rocket is carefully crafted to ensure the greatest productivity and reliability with the fewest surprises. Our goal is to make Rocket the obvious choice across all languages.
Accomplishing this takes time, and our efforts extend to the entire ecosystem. For example, work for Rocket v0.5 included:
- Fixing correctness issues in
x509-parser
. - Reporting multiple
correctness issues in
deadpool
. - Fixing a major usability issue in
async-stream
. - Creating a brand new configuration library.
- Updating,
fixing, and
maintaining
multer
. - Significantly improving
async_trait
correctness and usability. - Porting
Pattern
APIs to stable. - Porting macro diagnostics to stable.
- Creating a brand new byte unit library.
- Fixing a bug in
rustc
'slibtest
.
A version of Rocket is released whenever it is feature-complete and exceeds feature, security, and usability parity with the previous version. As a result, specifying a release date is nearly impossible. We are always willing to delay a release if these properties are not readily evident.
We know it can be frustrating, but we hope you'll agree that Rocket is worth the wait.
How To
Can I, and if so how, do I use WebSockets? #
Rocket doesn't support WebSockets quite yet. We're working on it.
That being said, Rocket does suport Server-Sent Events, which allows for real-time unidirectional communication from the server to the client. This is often sufficient for many of the applications that WebSockets are typically used for. For instance, the chat example uses SSE to implement a real-time, multiroom chat application.
Should I use global state via something like `lazy_static!`? #
No. Rocket's managed state provides a better alternative.
While it may be convenient or comfortable to use global state, the downsides are numerous. They include:
- The inability to test your application with different state.
- The inability to run your application on different threads with different state.
- The inability to know the state a route accesses by looking at its signature.
How do I handle file uploads? What is this "multipart" in my stream? #
For a quick example on how to handle file uploads, see multipart forms.
File uploads are transmitted by the browser as multipart form submissions,
which Rocket handles natively as a DataField
. The TempFile
form guard
can accept a DataField
and stream the data to disk to then be persisted.
How do I get an `&Request` in a handler? #
You don't!
Rocket's philosophy is that as much of the request should be validated and
converted into useful typed values before being processed. Allowing a
Request
to be handled directly is incompatible with this idea.
Instead, Rocket's handlers work through guards, reified as traits, which validate and extract parts of a request as needed. Rocket automatically invokes these guards for you, so custom guards are write-once-use-everywhere. Rocket won't invoke handlers that depend on guards that fail. This way, handlers only deal with fully validated, typed, secure values.
Rocket provides all of the guard implementations you would expect out-of-the-box, and you can implement your own, too. See the following:
- Parameter Guards:
FromParam
- Multi-Segment Guards:
FromSegments
- Data Guards:
FromData
- Form Guards:
FromFrom
- Request Guards:
FromRequest
How do I add a header to a response? #
That depends on the header!
Any "transport" headers (Content-Length
, Transfer-Encoding
, etc.) are
automatically set by Rocket and cannot be directly overridden for correctness
reasons. The rest are set by a type's Responder
implementation.
Status
Rocket automatically sets a Status header for all responses. If the Responder
doesn't explicitly set a status, it defaults to 200
. Responders like
Option<T>
, however, do set the status. See the Responder
docs for
details, and the status
module for details on setting a custom Status or
overriding an existing one.
Content-Type
Rocket automatically sets a Content-Type header for most types it implements
Responder
for, so in the common case, there's nothing to do. This includes
types like &str
, &[u8]
, NamedFile
, and so on. The content
module docs
have details on setting a custom Content-Type or overriding an existing one.
Everything Else
To add a custom header, you'll need a custom Responder
. Not to worry!
Responder
can be derived in almost all
cases. If a type for the header you want to add already exists, you can directly
derive Responder
for a struct that contains the header value, which adds the
header to the response:
# #[macro_use] extern crate rocket;
# use rocket::http::Header;
# type HeaderType = Header<'static>;
# impl<T> From<T> for MyResponder<T> {
# fn from(inner: T) -> Self {
# MyResponder { inner, header: Header::new("X-My-Header", "some value") }
# }
# }
#[derive(Responder)]
struct MyResponder<T> {
inner: T,
header: HeaderType,
}
#[get("/")]
fn with_header() -> MyResponder<&'static str> {
MyResponder::from("Hello, world!")
}
A HeaderType
won't exist for custom headers, but you can define your own type.
As long as it implements Into<Header>
for Rocket's Header
, the type can be
used as a field in derived struct.
You can always implement Responder
directly. Make sure to leverage existing
responders in your implementation. For example, don't serialize JSON manually.
Instead, use the existing Json
responder, like in the example below:
# #[derive(rocket::serde::Serialize)]
# #[serde(crate = "rocket::serde")]
# struct Person { name: String, age: usize };
use rocket::request::Request;
use rocket::response::{self, Response, Responder};
use rocket::serde::json::Json;
impl<'r> Responder<'r, 'static> for Person {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
Response::build_from(Json(&self).respond_to(req)?)
.raw_header("X-Person-Name", self.name)
.raw_header("X-Person-Age", self.age.to_string())
.ok()
}
}
How do I make one handler return different responses or status codes? #
If you're returning two different responses, use a Result<T, E>
or an
Either<A, B>
.
If you need to return more than two kinds, derive a custom Responder
enum
:
# use rocket::response::Responder;
use rocket::fs::NamedFile;
use rocket::http::ContentType;
#[derive(Responder)]
enum Error<'r, T> {
#[response(status = 400)]
Unauthorized(T),
#[response(status = 404)]
NotFound(NamedFile),
#[response(status = 500)]
A(&'r str, ContentType),
}
How do I make Rocket reload automatically when I change source code? #
In debug mode, Rocket automatically reloads templates for you. So if all you need is live template reloading, Rocket's got you covered.
For everything else, you'll need to use an external tool like cargo-watch
,
watchexec
or entr
. With cargo-watch
, you can automatically rebuild and
run a Rocket application by executing:
cargo watch -x run
To only restart on successful compilations, see this note.
How do I access managed state outside of a Rocket-related context? #
Use an Arc
, like this:
# use rocket::*;
use std::sync::Arc;
#[launch]
fn rocket() -> _ {
# struct MyState;
let state = Arc::new(MyState);
let external = state.clone();
std::thread::spawn(move || {
let use_state = external;
});
rocket::build().manage(state)
}
How do I make Rocket a _part_ of my application as opposed to the whole thing? #
If you're developing an application where an HTTP server is a part of the
application instead of being the entire thing, use the #[main]
attribute and
manually call launch()
:
#[rocket::main]
async fn main() {
# let should_start_server = false;
if should_start_server {
let result = rocket::build().launch().await;
} else {
// do something else
}
}
The cost to using the attribute is imperceptible and guarantees compatibility with Rocket's async I/O.
Debugging
Is example `foo` broken? It doesn't work for me. #
Almost certainly not.
Every example and code snippet you see in published documentation is tested by the CI on every commit, and we only publish docs that pass the CI. Unless the CI environment is broken, the examples cannot be wrong.
Common mistakes when running examples include:
- Looking at an example for version
y
but depending on versionx
. Select the proper git tag! - Looking at outdated examples on StackOverflow or Google. Check the date/version!
- Not configuring the correct dependencies. See the example's
Cargo.toml
!
The trait bound `rocket::Responder` (`FromRequest`, etc.) is not satisfied. #
If you're fairly certain a type implements a given Rocket trait but still get an error like:
error[E0277]: the trait bound `Foo: Responder<'_, '_>` is not satisfied
--> src\main.rs:4:20
|
4 | fn foo() -> Foo
| ^^^ the trait `Responder<'_, '_>` is not implemented for `Foo`
|
= note: required by `respond_to`
...then you're almost certainly depending on libraries which depend on different
versions of rocket
. A common mistake is to depend on a contrib
library from
git while also depending on a crates.io
version of Rocket or vice-versa:
rocket = "0.5.0-rc.1"
rocket_db_pools = { git = "https://github.com/SergioBenitez/Rocket.git" }
This is never correct. In Rust, types from two different versions of a library
or from different providers (like git
vs. crates.io
) are always considered
distinct, even if they have the same name. Therefore, even if a type implements
a trait from one library, it does not implement the trait from the other
library (since it is considered to be a different, distinct library). In
other words, you can never mix two different published versions of Rocket, a
published version and a git
version, or two instances from different git
revisions.