2017-04-17 02:48:59 +00:00
|
|
|
# Overview
|
|
|
|
|
|
|
|
Rocket provides primitives to build web servers and applications with Rust: the
|
|
|
|
rest is up to you. In short, Rocket provides routing, pre-processing of
|
|
|
|
requests, and post-processing of responses. Your application code instructs
|
|
|
|
Rocket on what to pre-process and post-process and fills the gaps between
|
|
|
|
pre-processing and post-processing.
|
|
|
|
|
|
|
|
## Lifecycle
|
|
|
|
|
|
|
|
Rocket's main task is to listen for incoming web requests, dispatch the request
|
|
|
|
to the application code, and return a response to the client. We call the
|
|
|
|
process that goes from request to response: the _lifecycle_. We summarize the
|
|
|
|
lifecycle as the sequence of steps:
|
|
|
|
|
|
|
|
1. **Routing**
|
|
|
|
|
|
|
|
Rocket parses an incoming HTTP request into native structures that your code
|
|
|
|
operates on indirectly. Rocket determines which request handler to invoke by
|
|
|
|
matching against route attributes declared by your application.
|
|
|
|
|
|
|
|
2. **Validation**
|
|
|
|
|
|
|
|
Rocket validates the incoming request against types and request guards
|
|
|
|
present in the matched route. If validation fails, Rocket _forwards_ the
|
|
|
|
request to the next matching route or calls an _error handler_.
|
|
|
|
|
|
|
|
3. **Processing**
|
|
|
|
|
|
|
|
The request handler associated with the route is invoked with validated
|
|
|
|
arguments. This is the main business logic of the application. Processing
|
|
|
|
completes by returning a `Response`.
|
|
|
|
|
|
|
|
4. **Response**
|
|
|
|
|
|
|
|
The returned `Response` is processed. Rocket generates the appropriate HTTP
|
|
|
|
response and sends it to the client. This completes the lifecycle. Rocket
|
|
|
|
continues listening for requests, restarting the lifecycle for each incoming
|
|
|
|
request.
|
|
|
|
|
|
|
|
The remainder of this section details the _routing_ phase as well as additional
|
|
|
|
components needed for Rocket to begin dispatching requests to request handlers.
|
|
|
|
The sections following describe the request and response phases.
|
|
|
|
|
|
|
|
## Routing
|
|
|
|
|
|
|
|
Rocket applications are centered around routes and handlers.
|
|
|
|
|
|
|
|
A _handler_ is simply a function that takes an arbitrary number of arguments and
|
|
|
|
returns any arbitrary type. A _route_ is a combination of:
|
|
|
|
|
|
|
|
* A set of parameters to match an incoming request against.
|
|
|
|
* A handler to process the request and return a response.
|
|
|
|
|
|
|
|
The parameters to match against include static paths, dynamic paths, path
|
|
|
|
segments, forms, query strings, request format specifiers, and body data. Rocket
|
|
|
|
uses attributes, which look like function decorators in other languages, to make
|
|
|
|
declaring routes easy. Routes are declared by annotating a function, the
|
|
|
|
handler, with the set of parameters to match against. A complete route
|
|
|
|
declaration looks like this:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
#[get("/world")] // <- route attribute
|
|
|
|
fn world() -> &'static str { // <- request handler
|
|
|
|
"Hello, world!"
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
This declares the `world` route to match against the static path `"/world"` on
|
|
|
|
incoming `GET` requests. The `world` route is simple, but additional route
|
|
|
|
parameters are necessary when building more interesting applications. The
|
|
|
|
[Requests](/guide/requests) section describes the available options for
|
|
|
|
constructing routes.
|
|
|
|
|
|
|
|
## Mounting
|
|
|
|
|
|
|
|
Before Rocket can dispatch requests to a route, the route needs to be _mounted_.
|
|
|
|
Mounting a route is like namespacing it. Routes are mounted via the `mount`
|
|
|
|
method on a `Rocket` instance. Rocket instances can be created with the
|
|
|
|
`ignite()` static method.
|
|
|
|
|
|
|
|
The `mount` method takes **1)** a path to namespace a list of routes under, and
|
|
|
|
**2)** a list of route handlers through the `routes!` macro. The `routes!` macro
|
|
|
|
ties Rocket's code generation to your application.
|
|
|
|
|
|
|
|
For instance, to mount the `world` route we declared above, we would use the
|
|
|
|
following code:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
rocket::ignite().mount("/hello", routes![world])
|
|
|
|
```
|
|
|
|
|
|
|
|
Altogether, this creates a new `Rocket` instance via the `ignite` function and
|
|
|
|
mounts the `world` route to the `"/hello"` path. As a result, `GET` requests to
|
|
|
|
the `"/hello/world"` path will be directed to the `world` function.
|
|
|
|
|
|
|
|
### Namespacing
|
|
|
|
|
|
|
|
When a route is declared inside a module other than the root, you may find
|
|
|
|
yourself with unexpected errors when mounting:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
mod other {
|
|
|
|
#[get("/world")]
|
|
|
|
pub fn world() -> &'static str {
|
|
|
|
"Hello, world!"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
use other::world;
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
// error[E0425]: cannot find value `static_rocket_route_info_for_world` in this scope
|
|
|
|
rocket::ignite().mount("/hello", routes![world])
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
This occurs because the `routes!` macro implicitly converts the route's name
|
|
|
|
into the name of a structure generated by Rocket's code generation. The solution
|
|
|
|
is to name the route by a module path instead:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
rocket::ignite().mount("/hello", routes![other::world])
|
|
|
|
```
|
|
|
|
|
|
|
|
## Launching
|
|
|
|
|
|
|
|
Now that Rocket knows about the route, you can tell Rocket to start accepting
|
|
|
|
requests via the `launch` method. The method starts up the server and waits for
|
|
|
|
incoming requests. When a request arrives, Rocket finds the matching route and
|
|
|
|
dispatches the request to the route's handler.
|
|
|
|
|
|
|
|
We typically call `launch` from the `main` function. Our complete _Hello,
|
|
|
|
world!_ application thus looks like:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
#![feature(plugin)]
|
|
|
|
#![plugin(rocket_codegen)]
|
|
|
|
|
|
|
|
extern crate rocket;
|
|
|
|
|
|
|
|
#[get("/world")]
|
|
|
|
fn world() -> &'static str {
|
|
|
|
"Hello, world!"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
rocket::ignite().mount("/hello", routes![world]).launch();
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Note that we've added the `#![feature(plugin)]` and `#![plugin(rocket_codegen)]`
|
|
|
|
lines to tell Rust that we'll be using Rocket's code generation plugin. We've
|
|
|
|
also imported the `rocket` crate into our namespace via `extern crate rocket`.
|
|
|
|
Finally, we call the `launch` method in the `main` function.
|
|
|
|
|
|
|
|
Running the application, the console shows:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
🔧 Configured for development.
|
|
|
|
=> address: localhost
|
|
|
|
=> port: 8000
|
|
|
|
=> log: normal
|
|
|
|
=> workers: {logical cores}
|
|
|
|
🛰 Mounting '/world':
|
|
|
|
=> GET /hello/world
|
|
|
|
🚀 Rocket has launched from http://localhost:8000...
|
|
|
|
```
|
|
|
|
|
|
|
|
If we visit `localhost:8000/hello/world`, we see `Hello, world!`, exactly as
|
|
|
|
we expected.
|
|
|
|
|
|
|
|
A version of this example's complete crate, ready to `cargo run`, can be found
|
|
|
|
on
|
2017-04-17 23:21:56 +00:00
|
|
|
[GitHub](https://github.com/SergioBenitez/Rocket/tree/v0.2.6/examples/hello_world).
|
2017-04-17 02:48:59 +00:00
|
|
|
You can find dozens of other complete examples, spanning all of Rocket's
|
|
|
|
features, in the [GitHub examples
|
2017-04-17 23:21:56 +00:00
|
|
|
directory](https://github.com/SergioBenitez/Rocket/tree/v0.2.6/examples/).
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
## Configuration
|
|
|
|
|
|
|
|
At any point in time, a Rocket application is operating in a given
|
|
|
|
_configuration environment_. There are three such environments:
|
|
|
|
|
|
|
|
* `development` (short: `dev`)
|
|
|
|
* `staging` (short: `stage`)
|
|
|
|
* `production` (short: `prod`)
|
|
|
|
|
|
|
|
Without any action, Rocket applications run in the `development` environment.
|
|
|
|
The environment can be changed via the `ROCKET_ENV` environment variable. For
|
|
|
|
example, to launch the `Hello, world!` application in the `staging` environment,
|
|
|
|
we can run:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
ROCKET_ENV=stage cargo run
|
|
|
|
```
|
|
|
|
|
|
|
|
You'll likely need `sudo` for the command to succeed since `staging` defaults to
|
|
|
|
listening on port `80`. Note that you can use the short or long form of the
|
|
|
|
environment name to specify the environment, `stage` _or_ `staging` here. Rocket
|
|
|
|
tells us the environment we have chosen and its configuration when it launches:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
$ sudo ROCKET_ENV=staging cargo run
|
|
|
|
|
|
|
|
🔧 Configured for staging.
|
|
|
|
=> address: 0.0.0.0
|
|
|
|
=> port: 80
|
|
|
|
=> log: normal
|
|
|
|
=> workers: {logical cores}
|
|
|
|
🛰 Mounting '/':
|
|
|
|
=> GET /
|
|
|
|
🚀 Rocket has launched from http://0.0.0.0:80...
|
|
|
|
```
|
|
|
|
|
|
|
|
Configuration settings can be changed in one of two ways: via the `Rocket.toml`
|
|
|
|
configuration file, or via environment variables.
|
|
|
|
|
|
|
|
### Configuration File
|
|
|
|
|
|
|
|
A `Rocket.toml` file can be used to specify the configuration parameters for
|
|
|
|
each environment. The file is optional. If it is not present, the default
|
|
|
|
configuration parameters are used.
|
|
|
|
|
|
|
|
The file must be a series of TOML tables, at most one for each environment and
|
|
|
|
an optional "global" table, where each table contains key-value pairs
|
|
|
|
corresponding to configuration parameters for that environment. If a
|
|
|
|
configuration parameter is missing, the default value is used. The following is
|
|
|
|
a complete `Rocket.toml` file, where every standard configuration parameter is
|
|
|
|
specified with the default value:
|
|
|
|
|
|
|
|
```toml
|
|
|
|
[development]
|
|
|
|
address = "localhost"
|
|
|
|
port = 8000
|
|
|
|
workers = max(number_of_cpus, 2)
|
|
|
|
log = "normal"
|
|
|
|
|
|
|
|
[staging]
|
|
|
|
address = "0.0.0.0"
|
|
|
|
port = 80
|
|
|
|
workers = max(number_of_cpus, 2)
|
|
|
|
log = "normal"
|
|
|
|
|
|
|
|
[production]
|
|
|
|
address = "0.0.0.0"
|
|
|
|
port = 80
|
|
|
|
workers = max(number_of_cpus, 2)
|
|
|
|
log = "critical"
|
|
|
|
```
|
|
|
|
|
|
|
|
The `workers` parameter is computed by Rocket automatically; the value above is
|
|
|
|
not valid TOML syntax.
|
|
|
|
|
|
|
|
The "global" pseudo-environment can be used to set and/or override configuration
|
|
|
|
parameters globally. A parameter defined in a `[global]` table sets, or
|
|
|
|
overrides if already present, that parameter in every environment. For example,
|
|
|
|
given the following `Rocket.toml` file, the value of `address` will be
|
|
|
|
`"1.2.3.4"` in every environment:
|
|
|
|
|
|
|
|
```toml
|
|
|
|
[global]
|
|
|
|
address = "1.2.3.4"
|
|
|
|
|
|
|
|
[development]
|
|
|
|
address = "localhost"
|
|
|
|
|
|
|
|
[production]
|
|
|
|
address = "0.0.0.0"
|
|
|
|
```
|
|
|
|
|
|
|
|
### Extras
|
|
|
|
|
|
|
|
In addition to overriding default configuration parameters, a configuration file
|
|
|
|
can also define values for any number of _extra_ configuration parameters. While
|
|
|
|
these parameters aren't used by Rocket directly, other libraries, or your own
|
|
|
|
application, can use them as they wish. As an example, the
|
|
|
|
[Template](https://api.rocket.rs/rocket_contrib/struct.Template.html) type
|
|
|
|
accepts a value for the `template_dir` configuration parameter. The parameter
|
|
|
|
can be set in `Rocket.toml` as follows:
|
|
|
|
|
|
|
|
```toml
|
|
|
|
[development]
|
|
|
|
template_dir = "dev_templates/"
|
|
|
|
|
|
|
|
[production]
|
|
|
|
template_dir = "prod_templates/"
|
|
|
|
```
|
|
|
|
|
|
|
|
This sets the `template_dir` extra configuration parameter to `"dev_templates/"`
|
|
|
|
when operating in the `development` environment and `"prod_templates/"` when
|
|
|
|
operating in the `production` environment. Rocket will prepend the `[extra]` tag
|
|
|
|
to extra configuration parameters when launching:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
🔧 Configured for development.
|
|
|
|
=> ...
|
|
|
|
=> [extra] template_dir: "dev_templates/"
|
|
|
|
```
|
|
|
|
|
|
|
|
### Environment Variables
|
|
|
|
|
|
|
|
All configuration parameters, including extras, can be overridden through
|
|
|
|
environment variables. To override the configuration parameter `{param}`, use an
|
|
|
|
environment variable named `ROCKET_{PARAM}`. For instance, to override the
|
|
|
|
"port" configuration parameter, you can run your application with:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
ROCKET_PORT=3721 cargo run
|
|
|
|
|
|
|
|
🔧 Configured for staging.
|
|
|
|
=> ...
|
|
|
|
=> port: 3721
|
|
|
|
```
|
|
|
|
|
|
|
|
Environment variables take precedence over all other configuration methods: if a
|
|
|
|
variable is set, it will be used as that parameter's value.
|