# Rocket v0.4: Typed URIs, Database Support, Revamped Queries, & More!

Posted by Sergio Benitez on December 08, 2018

I am elated to announce that the next major release of Rocket is now available! Rocket 0.4 is a step forward in every direction: it is **packed** with features and improvements that increase developer productivity, improve application security and robustness, provide new opportunities for extensibility, and deliver a renewed degree of toolchain stability. Rocket 0.4 is the culmination of more than a year of development. During this time, more than 600 changes were committed, almost 400 issues were closed, and over 165 pull requests were submitted. The Rocket community has proved steadfast in its support: a sincere thank you to everyone involved! ## About Rocket Rocket is a web framework for Rust with a focus on usability, security, and performance. Rocket makes it simple to write fast, secure web applications without sacrificing flexibility or type safety. Not already using Rocket? Join the tens of thousands of users and hundreds of companies happily using Rocket today! Rocket's extensive documentation makes it easy. Get started now by [reading through the guide](@guide-v0.4) or learning more from [the overview](../../overview). ## What's New? Rocket 0.4 is the largest release to date by a _wide_ margin. It is packed with hundreds of changes. We highlight the largest of them here. For a complete description of everything new and different in 0.4, please see the [CHANGELOG]. [CHANGELOG]: https://github.com/rwf2/Rocket/blob/v0.4.0/CHANGELOG.md#version-040-dec-06-2018 ### Maintainers += 1 An open source project is as much about the people as it is about the code. This is why I am delighted to welcome [@jebrosen] as Rocket's first co-maintainer! Jeb is directly responsible for several of the new features in 0.4, has painstakingly code reviewed many other changes, and actively answers questions and resolves issues on GitHub, IRC, and offline. Needless to say, Rocket is a better project thanks to you, Jeb. Welcome! [@jebrosen]: https://github.com/jebrosen ### Codegen Rewrite In 0.4, the [`rocket_codegen`] crate has been entirely rewritten to use to-be-stable procedural macro APIs where it previously used private, unstable `rustc` APIs. While this is largely an internal change, it has big, positive implications for all Rocket users. First and foremost, the path to Rocket on stable is now clearly in sight. While there are still hurdles to overcome, we are actively working with the Rust team to make Rocket on stable a reality as soon as possible. We expect the next major Rocket release to support the stable channel. Second, but equally important, we expect breakages due to nightly changes to drop dramatically, likely to zero. This means that Rocket is largely already _de-facto_ toolchain stable. The new prelude import for Rocket applications is: ```diff - #![feature(plugin)] - #![plugin(rocket_codegen)] + #![feature(proc_macro_hygiene, decl_macro)] - extern crate rocket; + #[macro_use] extern crate rocket; ``` [`rocket_codegen`] should **_not_** be a direct dependency. Remove it from your `Cargo.toml`: ```diff [dependencies] - rocket = "0.3" + rocket = "0.4" - rocket_codegen = "0.3" ``` [`rocket_codegen`]: https://api.rocket.rs/v0.4/rocket_codegen/index.html ### Typed URIs Rocket 0.4 introduces the [`uri!`] macro, allowing you to construct URIs to routes in a robust, type-safe, and URI-safe manner. Type or route parameter mismatches are caught at compile-time, and changes to route URIs are automatically reflected in the generated URIs. To illustrate, consider the following route: ```rust #[get("/person/?")] fn person(name: String, age: Option) ``` URIs to this `person` route can be created as follows: ```rust // with unnamed parameters, in route URI declaration order let uri = uri!(person: "Mike Smith", 28); assert_eq!(uri.to_string(), "/person/Mike%20Smith?age=28"); // with named parameters, order irrelevant let uri = uri!(person: name = "Mike", age = 28); let uri = uri!(person: age = 28, name = "Mike"); assert_eq!(uri.to_string(), "/person/Mike?age=28"); // with a specific mount-point let uri = uri!("/api", person: name = "Mike", age = 28); assert_eq!(uri.to_string(), "/api/person/Mike?age=28"); // with optional query parameters ignored let uri = uri!(person: "Mike", _); let uri = uri!(person: name = "Mike", age = _); assert_eq!(uri.to_string(), "/person/Mike"); ``` Should your route's URI change in an incompatible manner, or should you mistype parameters, Rocket informs you of the error at compile-time with a helpful message: ```rust error: person route uri expects 2 parameters but 1 was supplied --> examples/uri/src/main.rs:9:29 | 9 | uri!(person: "Mike Smith"); | ^^^^^^^^^^^^ | = note: expected parameters: name: String, age: Option ``` The same applies to type errors: Rocket informs you of any type errors at compile-time as well: ```rust error: the trait bound u8: FromUriParam is not satisfied --> examples/uri/src/main.rs:9:35 | 9 | uri!(person: age = "10", name = "Mike"); | ^^^^ FromUriParam is not implemented for u8 | ``` We recommend that `uri!` is exclusively used when constructing route URIs. For more information on typed URIs, see the new [Typed URIs] guide section and the [`uri!`] macro documentation. [`uri!`]: @api-v0.4/rocket_codegen/macro.uri.html [Typed URIs]: @guide-v0.4/responses/#typed-uris ### Database Support Rocket now includes built-in, ORM-agnostic support for database connection pooling. More specifically, Rocket allows you to easily configure and connect your Rocket application to databases through connection pools in three simple, largely automated steps: 1. Configure databases in `Rocket.toml`. 2. Associate a request guard type and fairing with each database. 3. Use the request guard to retrieve a connection in a handler. As an example, for a Diesel-based SQLite database named `sqlite_logs`, your `Rocket.toml` would record the URL to the database in the `databases` table: ```toml [global.databases] sqlite_logs = { url = "/path/to/database.sqlite" } ``` In the application, a unit-like `struct` with one internal type (the database connection) is decorated with the `#[database]` attribute and the name of the configured database. This generates a fairing which must then be attached: ```rust #[database("sqlite_logs")] struct LogsDbConn(diesel::SqliteConnection); rocket::ignite().attach(LogsDbConn::fairing()) ``` That's it! Whenever a connection to the database is needed, the type can be used as a request guard: ```rust #[get("/logs/")] fn get_logs(conn: LogsDbConn, id: usize) -> Result { logs::filter(id.eq(log_id)).load(&conn) } ``` For more information on Rocket's database support, see the new [Database] guide section and the [`rocket_contrib::databases`] module documentation. [Database]: @guide-v0.4/state/#databases [`rocket_contrib::databases`]: @api-v0.4/rocket_contrib/databases/index.html ### Revamped Queries In Rocket 0.4, query string handling has been completely overhauled, resolving some of the most called for requests in Rocket's history ([#608]). The new query handling route syntax and semantics were designed with the following goals in mind: * Enable matching of static query components. * No special-casing of any kind, preferring type-driven flows. * Ad-hoc matching of specific query key/value pairs. * Lenient parsing by default, allowing missing parameters. * Order-independent matching of query parameters. To illustrate the new system in action, consider the following route: ```rust #[derive(FromForm)] struct DogDetails { color: Color, height: Inches, weight: Pounds } #[get("/animal?dog&&&")] fn dog(name: String, nickname: Option, rest: Form) ``` This route matches any `GET` request with a path of `/animal`, a static query component of `dog`, and key/value parameters of `color`, `height`, and `weight` that validate as `Color`, `Inches`, and `Pounds`, respectively. Furthermore, it optionally accepts a key/value parameter of `nickname`. If the value is present, `nickname` will be `Some`; if it is not, `nickname` will be `None`. Single parameters (``) like `name` and `nickname` are validated using the existing [`FromFormValue`] trait while trailing parameters (``) are validated using the new [`FromQuery`] trait. Both traits are user implementable, and [`FromFormValue`] can be derived. For more details on handling query strings, see the new [Query Strings] guide section and the updated [`route` attribute] documentation. [`FromFormValue`]: @api-v0.4/rocket/request/trait.FromFormValue.html [`FromQuery`]: @api-v0.4/rocket/request/trait.FromQuery.html [`route` attribute]: @api-v0.4/rocket_codegen/attr.get.html [Query Strings]: @guide-v0.4/requests/#query-strings [#608]: https://github.com/rwf2/Rocket/issues/608 ### Stateful Handlers The type of a handler has been generalized in 0.4 to any type that implements the new [`Handler`] trait. Among other things, this allows handlers to refer to internal state during request handling. The new [`StaticFiles`] `contrib` type uses this functionality to provide easier-than-ever static file serving. For example, to make local files from a `/static` directory accessible at `/public`, you need simply write: ```rust fn main() { rocket::ignite() .mount("/public", StaticFiles::from("/static")) .launch(); } ``` We encourage users to explore the new `Handler` API and contribute libraries with pluggable handlers! For more details, see the [`Handler`] documentation. [`Handler`]: @api-v0.4/rocket/trait.Handler.html [`StaticFiles`]: @api-v0.4/rocket_contrib/serve/struct.StaticFiles.html ### Responder Derive In Rocket 0.4, the [`Responder`] trait can be derived for `enum`s and `struct`s with named fields. This greatly simplifies returning multiple types of responses from a single handler. To illustrate, consider a route that returns either a `Json` structure for 401 (unauthorized) errors or a `NamedFile` with a dynamic Content-Type for 404 (not found) errors. To accomplish this previously, `Result` values could be arbitrarily nested, an unappealing and semantically incorrect approach. Alternatively, an `enum` could be declared with the appropriate variants, and `Responder` could be manually implemented for the `enum`. As of 0.4, that implementation can be automatically derived: ```rust #[derive(Responder, Debug)] enum Error { #[response(status = 401)] Unauthorized(Json), #[response(status = 404)] NotFound(NamedFile, ContentType), } ``` A value of this type can then be returned from a handler or used as part of wrapping responders: ```rust #[get("/")] fn handler(user: Option, item: Option) -> Result { if user.is_none() { Err(Error::Unauthorized(..)) } else if item.is_none() { Err(Error::NotFound(..)) } else { Ok(..) } } ``` The status for each variant will be automatically set to the value of the `status` variant attribute, and fields beyond the first will be added as headers to the response (here, `ContentType`). For more on using the `Responder` derive, see the new [Custom Responders] guide section and the [`Responder` derive] documentation. [Custom Responders]: @guide-v0.4/responses/#custom-responders [`Responder` derive]: @api-v0.4/rocket_codegen/derive.Responder.html [`Responder`]: @api-v0.4/rocket/response/trait.Responder.html ### Live Template Reloading Rocket 0.4 automatically reloads changed templates at runtime without requiring recompilation. This works on all major platforms. For security and performance reasons, live template reloading is only enabled when the application is compiled in debug mode. There is no configuration necessary: this _just works_ out of the box! ### And Plenty More! In addition to the features highlighted above, Rocket 0.4 also contains the following new features: * Introduced [Request-Local State]. * Introduced [transforming] data guards via [`FromData::transform()`]. * Introduced the [`SpaceHelmet`] security and privacy headers fairing. * Private cookies are gated behind a `private-cookies` default feature. * Added [derive for `FromFormValue`]. * Added [`Template::custom()`] for customizing templating engines. * Cookies are automatically tracked and propagated by [`Client`]. * Private cookies can be added to local requests with [`LocalRequest::private_cookie()`]. * Release builds default to the `production` environment. * Keep-alive can be configured via the `keep_alive` configuration parameter. * Allow CLI colors and emoji to be disabled with `ROCKET_CLI_COLORS=off`. * Route `format` accepts [shorthands] such as `json` and `html`. * Implemented [`Responder` for `Status`]. * Added [`Response::cookies()`] for retrieving response cookies. * All logging is disabled when `log` is set to `off`. * Added [`Metadata`] guard for retrieving templating information. * The [`Uri`] type parses according to RFC 7230 into one of [`Origin`], [`Absolute`], or [`Authority`]. * Added [`Outcome::and_then()`], [`Outcome::failure_then()`], and [`Outcome::forward_then()`]. * Implemented `Responder` for `&[u8]`. * Any `T: Into>` can be [`mount()`]ed. * Added [`Request::get_query_value()`] for retrieving a query value by key. * Applications can launch without a working directory. * Added [`State::from()`] for constructing `State` values. [`SpaceHelmet`]: https://api.rocket.rs/v0.4/rocket_contrib/helmet/index.html [`State::from()`]: https://api.rocket.rs/v0.4/rocket/struct.State.html#method.from [Typed URIs]: https://rocket.rs/v0.4/guide/responses/#typed-uris [ORM agnostic database support]: https://rocket.rs/v0.4/guide/state/#databases [`Template::custom()`]: https://api.rocket.rs/v0.4/rocket_contrib/templates/struct.Template.html#method.custom [`LocalRequest::private_cookie()`]: https://api.rocket.rs/v0.4/rocket/local/struct.LocalRequest.html#method.private_cookie [`LocalRequest`]: https://api.rocket.rs/v0.4/rocket/local/struct.LocalRequest.html [shorthands]: https://api.rocket.rs/v0.4/rocket/http/struct.ContentType.html#method.parse_flexible [derive for `FromFormValue`]: https://api.rocket.rs/v0.4/rocket_codegen/derive.FromFormValue.html [derive for `Responder`]: https://api.rocket.rs/v0.4/rocket_codegen/derive.Responder.html [`Response::cookies()`]: https://api.rocket.rs/v0.4/rocket/struct.Response.html#method.cookies [`Client`]: https://api.rocket.rs/v0.4/rocket/local/struct.Client.html [Request-Local State]: https://rocket.rs/v0.4/guide/state/#request-local-state [`Metadata`]: https://api.rocket.rs/v0.4/rocket_contrib/templates/struct.Metadata.html [`Uri`]: https://api.rocket.rs/v0.4/rocket/http/uri/enum.Uri.html [`Origin`]: https://api.rocket.rs/v0.4/rocket/http/uri/struct.Origin.html [`Absolute`]: https://api.rocket.rs/v0.4/rocket/http/uri/struct.Absolute.html [`Authority`]: https://api.rocket.rs/v0.4/rocket/http/uri/struct.Authority.html [`Outcome::and_then()`]: https://api.rocket.rs/v0.4/rocket/enum.Outcome.html#method.and_then [`Outcome::forward_then()`]: https://api.rocket.rs/v0.4/rocket/enum.Outcome.html#method.forward_then [`Outcome::failure_then()`]: https://api.rocket.rs/v0.4/rocket/enum.Outcome.html#method.failure_then [`StaticFiles`]: https://api.rocket.rs/v0.4/rocket_contrib/serve/struct.StaticFiles.html [live template reloading]: https://rocket.rs/v0.4/guide/responses/#live-reloading [`Handler`]: https://api.rocket.rs/v0.4/rocket/trait.Handler.html [`mount()`]: https://api.rocket.rs/v0.4/rocket/struct.Rocket.html#method.mount [`FromData::transform()`]: https://api.rocket.rs/v0.4/rocket/data/trait.FromData.html#tymethod.transform [transforming]: https://api.rocket.rs/v0.4/rocket/data/trait.FromData.html#transforming [query string handling]: https://rocket.rs/v0.4/guide/requests/#query-strings [Default rankings]: https://rocket.rs/v0.4/guide/requests/#default-ranking [`Request::get_query_value()`]: https://api.rocket.rs/v0.4/rocket/struct.Request.html#method.get_query_value [`Responder` for `Status`]: https://rocket.rs/v0.4/guide/responses/#status ## Breaking Changes This release includes many breaking changes. Please see the [CHANGELOG](https://github.com/rwf2/Rocket/blob/v0.3.0/CHANGELOG.md#breaking-changes) for a complete list of breaking changes along with details on handling the breaking change in existing applications. Rocket 0.3 will continue as a security maintenance release _only_. All users are encouraged to migrate their applications to 0.4. ## General Improvements In addition to new features, Rocket saw the following improvements: * Log messages now refer to routes by name. * Collision errors on launch name the colliding routes. * Launch fairing failures refer to the failing fairing by name. * The default `403` catcher now references authorization, not authentication. * Private cookies are set to `HttpOnly` and are given an expiration date of 1 week by default. * A [Tera templates example] was added. * All macros, derives, and attributes are individually documented in [`rocket_codegen`]. * Invalid client requests receive a response of `400` instead of `500`. * Response bodies are reliably stripped on `HEAD` requests. * Added a default catcher for `504: Gateway Timeout`. * Configuration information is logged in all environments. * Use of `unsafe` was reduced from 9 to 2 in core library. * [`FormItems`] now parses empty keys and values as well as keys without values. * Added [`Config::active()`] as a shorthand for `Config::new(Environment::active()?)`. * Address/port binding errors at launch are detected and explicitly emitted. * [`Flash`] cookies are cleared only after they are inspected. * `Sync` bound on [`AdHoc::on_attach()`], [`AdHoc::on_launch()`] was removed. * [`AdHoc::on_attach()`], [`AdHoc::on_launch()`] accept an `FnOnce`. * Added [`Config::root_relative()`] for retrieving paths relative to the configuration file. * Added [`Config::tls_enabled()`] for determining whether TLS is actively enabled. * ASCII color codes are not emitted on versions of Windows that do not support them. * Added FLAC (`audio/flac`), Icon (`image/x-icon`), WEBA (`audio/webm`), TIFF (`image/tiff`), AAC (`audio/aac`), Calendar (`text/calendar`), MPEG (`video/mpeg`), TAR (`application/x-tar`), GZIP (`application/gzip`), MOV (`video/quicktime`), MP4 (`video/mp4`), ZIP (`application/zip`) as known media types. * Added `.weba` (`WEBA`), `.ogv` (`OGG`), `.mp4` (`MP4`), `.mpeg4` (`MP4`), `.aac` (`AAC`), `.ics` (`Calendar`), `.bin` (`Binary`), `.mpg` (`MPEG`), `.mpeg` (`MPEG`), `.tar` (`TAR`), `.gz` (`GZIP`), `.tif` (`TIFF`), `.tiff` (`TIFF`), `.mov` (`MOV`) as known extensions. * Interaction between route attributes and declarative macros has been improved. * Generated code now logs through logging infrastructures as opposed to using `println!`. * Routing has been optimized by caching routing metadata. * [`Form`] and [`LenientForm`] can be publicly constructed. * Console coloring uses default terminal colors instead of white. * Console coloring is consistent across all messages. * `i128` and `u128` now implement [`FromParam`], [`FromFormValue`]. * The `base64` dependency was updated to `0.10`. * The `log` dependency was updated to `0.4`. * The `handlebars` dependency was updated to `1.0`. * The `tera` dependency was updated to `0.11`. * The `uuid` dependency was updated to `0.7`. * The `rustls` dependency was updated to `0.14`. * The `cookie` dependency was updated to `0.11`. [Tera templates example]: @github/examples/tera_templates [`FormItems`]: @api-v0.4/rocket/request/enum.FormItems.html [`Config::active()`]: @api-v0.4/rocket/config/struct.Config.html#method.active [`Flash`]: @api-v0.4/rocket/response/struct.Flash.html [`AdHoc::on_attach()`]: @api-v0.4/rocket/fairing/struct.AdHoc.html#method.on_attach [`AdHoc::on_launch()`]: @api-v0.4/rocket/fairing/struct.AdHoc.html#method.on_launch [`Config::root_relative()`]: @api-v0.4/rocket/struct.Config.html#method.root_relative [`Config::tls_enabled()`]: @api-v0.4/rocket/struct.Config.html#method.tls_enabled [`rocket_codegen`]: @api-v0.4/rocket_codegen/index.html [`FromParam`]: @api-v0.4/rocket/request/trait.FromParam.html [`FromFormValue`]: @api-v0.4/rocket/request/trait.FromFormValue.html [`Data`]: @api-v0.4/rocket/struct.Data.html [`Form`]: https://api.rocket.rs/v0.4/rocket/request/struct.Form.html [`LenientForm`]: https://api.rocket.rs/v0.4/rocket/request/struct.LenientForm.html ## What's Next? Rocket v0.5 is scheduled to be _at least_ as exciting as 0.4! As always, the focus continues to be usability, stability, security, and performance. With this in mind, the roadmap for 0.5 includes: 1. **Support for Rust Stable** ([#19]) Finally! Rocket 0.5 will compile and run on stable versions of the Rust compiler. 2. **Asynchronous Request Handling** ([#17]) In 0.5, Rocket will migrate to the latest asynchronous version of `hyper` and `futures` with compatibility for `async`/`await` syntax. Of utmost importance is preserving Rocket's usability. As such, these changes will be largely internal, with asynchronous I/O peeking over the covers _only_ when explicitly desired or required. As a side effect, we expect a substantial performance boost from the migration as well as resolution to long-standing issues. 3. **Multipart Form Support** ([#106]) The lack of built-in multipart form support makes handling file uploads and other submissions much more cumbersome than necessary. Rocket 0.5 will generalize its existing forms infrastructure to handle multipart forms. 4. **Stronger CSRF and XSS Protection** ([#14]) Since 0.3, Rocket uses `SameSite: Strict` private cookies to prevent CSRF attacks. This technique is only tenable in newer browsers. In 0.5, Rocket will protect against CSRF using more robust techniques. Rocket will also add support for automatic, browser-based XSS protection. [#17]: https://github.com/rwf2/Rocket/issues/17 [#19]: https://github.com/rwf2/Rocket/issues/19 [#106]: https://github.com/rwf2/Rocket/issues/106 [#14]: https://github.com/rwf2/Rocket/issues/14 ## Rocket v0.4 Contributors The following wonderful people helped make Rocket 0.4 happen:
  • Alexander Mielczarek
  • Alex Bowers
  • Alfie John
  • Alva Snædís
  • Ashley Williams
  • Beatriz Rizental
  • bohov
  • Christophe Courtaut
  • David Darrell
  • Desmond
  • Divyahans Gupta
  • Donald Robertson
  • EloD10
  • Eric Dattore
  • Henning Kowalk
  • Imron Alston
  • Jeb Rosen
  • kryptan
  • Kyle Clemens
  • lerina
  • Linus Unnebäck
  • Lukas Abfalterer
  • Marc Mettke
  • Max Furman
  • messense
  • Ning Sun
  • Philip Jenvey
  • Pyry Kontio
  • Richo Healey
  • Riley Trautman
  • Rolf Schmidt
  • Rukai
  • Sean Stangl
  • Sébastien Santoro
  • Sergio Benitez
  • Stanislav Ivanov
  • Tal Garfinkel
  • Tobias Stolzmann
  • Ville Hakulinen
  • Vishal Sodani
  • Zack Chandler
  • Zac Pullar-Strecker
Thank you all! Your contributions are **greatly** appreciated! Looking to help with Rocket's development? Head over to [Rocket's GitHub](https://github.com/rwf2/Rocket#contributing) and start contributing!