Clean up upgrade guide, FAQ. Mention FAQ more.

This commit is contained in:
Sergio Benitez 2021-08-29 16:55:05 -07:00
parent 010e762125
commit f38cbea898
4 changed files with 118 additions and 92 deletions

View File

@ -1,12 +1,12 @@
# Upgrading
Rocket v0.5 bring many new features and improvements over Rocket v0.4. Along
with new features, Rocket v0.5 also includes many changes that improve the
overall usability, stability, and security of the framework and applications
written in it. While the Rust compiler can guide you through many of these
changes, others require special attention. The intent of this guide is to guide
you through these changes and more, migrating your Rocket application to 0.5 and
reaping the benefits of new features and improvements.
Rocket v0.5 bring many new features and improvements over Rocket v0.4. Rocket
v0.5 also includes many changes that improve the overall usability, stability,
and security of the framework and applications written in it. While the Rust
compiler can guide you through many of these changes, others require special
attention. The intent of this guide is to guide you through these changes and
more, migrating your Rocket application to 0.5 and reaping the benefits of new
features and improvements.
This guide is _not_ intended to replace, but instead complement, a reading of
the [CHANGELOG]. The [CHANGELOG] should be considered required reading for all
@ -14,6 +14,15 @@ developers wishing to migrate their applications to Rocket v0.5.
[CHANGELOG]: @github/CHANGELOG.md
! note Don't panic!
Simply upgrading Rocket's version string to the `0.5` series will result in
_many_ `rustc` compiler errors. But don't let this phase you! The vast
majority of changes are simple renames and `#[async_trait]` attributions which
manifest in a cascading of errors. As such, resolving _one_ top-level issue,
typically requiring minimal, trivial changes, often resolves _many_ errors in
one go.
## Crate Organization
Rocket v0.5 incorporates an improved module structure and crate ecosystem.
@ -55,18 +64,16 @@ to `Cargo.toml`:
+ rocket_dyn_templates = { version = "0.1.0-rc.1", features = ["tera"] }
```
! note: `rocket_dyn_templates` _does not_ follow in version lock-step with
the `rocket` crate.
! note: `rocket_dyn_templates` (and co.) _does not_ follow in version lock-step
with the `rocket` crate.
This is intentional. The crate depends on many external dependencies which may
evolve at a different pace than Rocket itself. Allowing their versions to
diverge enables keeping dependencies up-to-date without breaking `rocket`
itself.
All features previously present in `rocket_contrib` are available elsewhere. The
[contrib graduation] section of the CHANGELOG contains full details on the
changes.
All features previously in `rocket_contrib` are available. Consult the [contrib
graduation] section of the CHANGELOG for full details.
[`rocket_dyn_templates`]: @api/rocket_dyn_templates
[`rocket_sync_db_pools`]: @api/rocket_sync_db_pools
@ -101,7 +108,7 @@ If you prefer to use Rust's stable release channel, you can switch to it using
```sh
## switch globally
rustup default nightly
rustup default stable
## switch locally
rustup override set stable
@ -110,9 +117,8 @@ rustup override set stable
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. As a result, the
development experience will continue to be better on nightly for the forseeable
future. For example, compiler diagnostics on `nightly` are more detailed and
accurate:
development experience will be superior on nightly for the forseeable future.
For example, compiler diagnostics on `nightly` are more detailed and accurate:
<details>
<summary>Example Diagnostic on Nightly</summary>
@ -179,7 +185,7 @@ 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.
At the same time, the `rocket::ignite()` function has been renamed to
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:
@ -204,18 +210,19 @@ Rocket v0.5 takes advantage of the latest developments in async I/O in Rust by
migrating to a fully asynchronous core powered by [`tokio`]. Specifically,
_every_ request is handled by an asynchronous task which internally calls one or
more request handlers. Asynchronous tasks are multiplexed on a [configurable
number of worker threads]. Though there is no limit on the number of tasks that
can run concurrently, at most `worker` tasks can be run in parallel.
number of worker threads]. Though there is no limit to the number of tasks that
can run concurrently, at most `worker` tasks can run in parallel.
The runtime can switch between tasks in a single worker thread _iff_ an `await`
point in reached. In other words, context switching is _cooperative_, _not_
preemptive. This _iff_ is critical: if an `await` point is _not_ reached, no
task switching can occur. As such, it is important that `await` points occur
periodically in a task so that tasks waiting to be scheduled are not starved.
The runtime can switch between tasks in a single worker thread _iff_ <small>(_if
and only if_)</small> an `await` point in reached. In other words, context
switching is _cooperative_, _not_ preemptive. This _iff_ is critical: if an
`await` point is _not_ reached, no task switching can occur. As such, it is
important that `await` points occur periodically in a task so that tasks waiting
to be scheduled are not starved.
In general, when working with `async` APIs, await points will occur naturally.
However, an application written for synchronous I/O, like all Rocket
applications prior to 0.4, must take great care to convert all synchronous,
In general, when working with `async` APIs, await points occur naturally.
However, an application written for synchronous I/O, including all Rocket
applications prior to v0.5, must take great care to convert all synchronous,
blocking I/O, to `async` I/O. This is because, as the name implies, blocking I/O
blocks a thread from making progress until the I/O result is available, meaning
that no tasks can be scheduled on the waiting thread, wasting valuable resources
@ -234,8 +241,8 @@ Common sources of blocking I/O and their `async` replacements include:
Unfortunately, the Rust compiler provides no support for identifying blocking
I/O via lints or compile-time checks: it is up to you to scan your application
for sources of blocking I/O and replace them with their `async` counterpart. If
no such counterpart exists, you must execute the I/O in its own thread by using
[`rocket::tokio::task::spawn_blocking`].
no such counterpart exists, you should execute the relevant I/O in its own
thread by using [`rocket::tokio::task::spawn_blocking`].
All of Rocket's I/O APIs have been updated to be `async`-safe.
This results in requiring `.await` calls for common APIs like [`NamedFile`]. To
@ -251,6 +258,11 @@ async fn index() -> Option<NamedFile> {
}
```
! warning: Non-`async` routes are _also_ executed on the `async` runtime.
A route that _isn't_ declared as `async` is _still_ executed on the `async`
runtime. As a result, it should not execute blocking I/O.
<details>
<summary>See a diff of the changes from v0.4.</summary>
@ -343,7 +355,7 @@ of truth for trait and method signatures.
## Configuration
Rocket's configuration system has been entirely revamped for 0.5. The
Rocket's configuration system has been entirely revamped for v0.5. The
[configuration](../configuration) section of the guide contains a full
walkthrough of the new system while the [general changes] section of the
CHANGELOG contains further details on configuration changes. We call out the
@ -366,7 +378,7 @@ detected.
The new system deals with "profiles" where there were previously "environments".
As opposed to environments, profiles:
* Can be arbitrarily named, and any number can exist.
* Can be arbitrarily named and any number can exist.
* Match Rust profiles in naming: `debug` and `release` are the default
profiles for the respective Rust compilation profile.
* Are programmatically selectable and configurable.
@ -449,7 +461,7 @@ Rocket v0.5 brings several major changes that affect routing:
Default route ranking now takes into account partially dynamic paths, increasing
the range of default ranks from `[-6, -1]` to `[-12, -1]`. The net effect is
that fewer routes collide by default, requiring less manual ranking. For
example, the following two routes collide in 0.4 but not in 0.5:
example, the following two routes collide in v0.4 but not in v0.5:
```rust
# use rocket::get;
@ -479,7 +491,7 @@ fn everything() { }
For smaller applications, you may find that _all_ manual ranks can be removed.
Larger applications may still require ranks to resolve ambiguities.
### Kleen Multi-Segments
### Kleene Multi-Segments
The multi-segment route parameter `<foo..>` now matches _zero or more_ segments,
a change from the previous _one_ or more segments. The implication is two-fold:
@ -587,10 +599,12 @@ Rocket v0.5 introduces entirely revamped [forms] with support for:
* [Ad-Hoc validation.](../requests#ad-hoc-validation)
Additionally, the [`FromForm` derive] has been substantially improved so that
nearly all custom implementations of `FromForm` or (the now defunct)
`FromFormValue` can be derived. Altogether, this means that any external crate
dependency for form handling and most custom `FromForm` or `FromFormValue`
implementations are unnecessary and should be removed.
nearly all custom implementations of `FromForm` or [`FromFormField`], which
replaces `FromFormValue` from v0.4, can be derived. Altogether, this means that
any external crate dependency for form handling and most custom `FromForm` or
`FromFormValue` implementations are unnecessary and should be removed.
[`FromFormField`]: @api/rocket/form/trait.FromFormField.html
### Multipart
@ -800,7 +814,8 @@ fn stream(n: Option<u64>) -> EventStream![] {
If you run into any issues upgrading, we encourage you to ask questions via
[GitHub discussions] or via chat at [`#rocket:mozilla.org`] on Matrix or the
bridged [`#rocket`] IRC channel at `irc.libera.chat`.
bridged [`#rocket`] IRC channel at `irc.libera.chat`. The [FAQ](../faq/) also
provides answers to commonly asked questions.
[GitHub discussions]: https://github.com/SergioBenitez/Rocket/discussions
[`#rocket:mozilla.org`]: https://chat.mozilla.org/#/room/#rocket:mozilla.org

View File

@ -11,7 +11,8 @@ If you find yourself having trouble developing Rocket applications, you can get
help via chat at [`#rocket:mozilla.org`] on Matrix or the bridged [`#rocket`]
IRC channel on Libera.Chat at `irc.libera.chat`. We recommend joining us on
[Matrix via Element]. If you prefer IRC, you can join via the [Kiwi IRC client]
or a client of your own.
or a client of your own. The [FAQ](../faq/) also provides answers to commonly
asked questions.
[`#rocket:mozilla.org`]: https://chat.mozilla.org/#/room/#rocket:mozilla.org
[`#rocket`]: https://kiwiirc.com/client/irc.libera.chat/#rocket

View File

@ -17,34 +17,35 @@ 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:
Rocket's core is small yet complete with respect to security and correctness. It
mainly consists of:
* Guard traits like [`FromRequest`] and [`FromData`].
* Derive macros for all commonly used traits.
* Derive macros for all common 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.
* Optional features for functionality like TLS, secrets, and so on.
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.
implemented entirely outside of Rocket while maintaining a first-class feel and
experience. 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.
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:
Unlike other frameworks, Rocket makes it its mission to help you avoid security
and correctness blunders. 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.
* A flexible, type-based [configuration](../configuration/) system.
* [Security and privacy headers](@api/rocket/shield/) by default.
* Zero-Copy RFC compliant [URI parsers](@api/rocket/http/uri).
* Safe, [typed URIs](@api/rocket/macro.uri.html) with compile-time checking.
* [Compile-time and launch-time route checking](@api/rocket/attr.route.html).
* A [testing framework](@api/rocket/local) with sync and `async` variants.
* Safe, exclusive access to fully decoded HTTP values.
* Mandatory data limits to prevent trivial DoS attacks.
* Mandatory [data limits](@api/rocket/data/struct.Limits.html) 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
@ -104,13 +105,15 @@ Can I use Rocket in production? Should I? It's only v0.x!
<div class="content">
We **enthusiastically** recommend using Rocket in production, with the following
caveats:
non-exhaustive list of caveats:
1. 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.
DDoS attacks or certain DoS attacks which can be mitigated by an external
service.
2. Use a TLS termination proxy for zero-downtown certificate rotation.
2. Use a TLS termination proxy (perhaps from 1.) for zero-downtown certificate
rotation.
3. Properly configure your databases and database pools, especially with
respect to the pool size.
@ -157,8 +160,8 @@ 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.
measurement was taken. In other words, it provides 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:
@ -228,7 +231,8 @@ 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.
surprises. Our goal is to make Rocket a compelling choice across _all_
languages.
Accomplishing this takes time, and our efforts extend to the entire ecosystem.
For example, work for Rocket v0.5 included:
@ -314,7 +318,7 @@ 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.
can accept a `DataField` and stream the data to disk for persistence.
</div>
</details>
@ -339,8 +343,8 @@ converted into useful typed values _before_ being processed. Allowing a
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.
won't invoke a handler with failing guards. 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:
@ -375,18 +379,17 @@ 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.
Rocket automatically sets a `Status` header for all responses. If a `Responder`
doesn't explicitly set a status, it defaults to `200`. Some responders, like
`Option<T>`, do set a status. See [`Responder`] 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
Rocket automatically sets a `Content-Type` header for 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.
details setting a custom `Content-Type` or overriding an existing one.
**Everything Else**
@ -424,9 +427,10 @@ 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:
Alternatively, 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:
```rust
# #[derive(rocket::serde::Serialize)]
@ -554,10 +558,7 @@ How do I make Rocket a _part_ of my application as opposed to the whole thing?
</summary>
<div class="content">
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()`]:
Use the `#[main]` attribute and manually call [`launch()`]:
```rust,no_run
#[rocket::main]
@ -624,23 +625,29 @@ error[E0277]: the trait bound `Foo: Responder<'_, '_>` is not satisfied
= 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:
...then you're almost certainly depending, perhaps transitively, on _two
different versions_ of a single library. For example, you may be depending on
`rocket` which depends on `time 0.3` while also depending directly on `time
0.2`. Or you may depending on `rocket` from `crates.io` while depending on a
library that depends on `rocket` from `git`. A common instance of this mistake
is to depend on a `contrib` library from git while also depending on a
`crates.io` version of Rocket or vice-versa:
```toml
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.
This is _never_ correct. If libraries or applications interact via types from a
common library, those libraries or applications _must_ specify the _same_
version of that common library. This is because 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.
</div>
</details>

View File

@ -14,6 +14,8 @@ aspect of Rocket. The sections are:
- **[Introduction](introduction/):** introduces Rocket and its philosophy.
- **[Quickstart](quickstart/):** presents the minimal steps necessary to
run your first Rocket application.
- **[Upgrading from v0.4](upgrading-from-0.4/):** a migration guide from v0.4
to v0.5.
- **[Getting Started](getting-started/):** a gentle introduction to getting
your first Rocket application running.
- **[Overview](overview/):** describes the core concepts of Rocket.
@ -38,7 +40,8 @@ aspect of Rocket. The sections are:
The official community support channels are [`#rocket:mozilla.org`] on Matrix
and the bridged [`#rocket`] IRC channel on Libera.Chat at `irc.libera.chat`. We
recommend joining us on [Matrix via Element]. If you prefer IRC, you can join
via the [Kiwi IRC client] or a client of your own.
via the [Kiwi IRC client] or a client of your own. The [FAQ](../faq/) also
provides answers to commonly asked questions.
[`#rocket:mozilla.org`]: https://chat.mozilla.org/#/room/#rocket:mozilla.org
[`#rocket`]: https://kiwiirc.com/client/irc.libera.chat/#rocket