2017-04-17 02:48:59 +00:00
|
|
|
|
###############################################################################
|
|
|
|
|
# Panels: displayed in a tabbed arrangement.
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
[[panels]]
|
|
|
|
|
name = "Routing"
|
|
|
|
|
checked = true
|
|
|
|
|
content = '''
|
|
|
|
|
Rocket's main task is to route incoming requests to the appropriate request
|
|
|
|
|
handler using your application's declared routes. Routes are declared using
|
|
|
|
|
Rocket's _route_ attributes. The attribute describes the requests that match the
|
|
|
|
|
route. The attribute is placed on top of a function that is the request handler
|
|
|
|
|
for that route.
|
|
|
|
|
|
|
|
|
|
As an example, consider the simple route below:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
#[get("/")]
|
|
|
|
|
fn index() -> &'static str {
|
|
|
|
|
"Hello, world!"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2021-06-27 00:10:57 +00:00
|
|
|
|
This `index` route matches any incoming HTTP `GET` request to `/`, the index.
|
|
|
|
|
The handler returns a `String`. Rocket automatically converts the string into a
|
|
|
|
|
well-formed HTTP response that includes the appropriate `Content-Type` and body
|
|
|
|
|
encoding metadata.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
[[panels]]
|
|
|
|
|
name = "Dynamic Params"
|
|
|
|
|
content = '''
|
2021-06-27 00:10:57 +00:00
|
|
|
|
Rocket automatically parses dynamic data in path segments into any desired type.
|
|
|
|
|
To illustrate, let's use the following route:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
#[get("/hello/<name>/<age>")]
|
2021-06-27 00:10:57 +00:00
|
|
|
|
fn hello(name: &str, age: u8) -> String {
|
2017-04-17 02:48:59 +00:00
|
|
|
|
format!("Hello, {} year old named {}!", age, name)
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2021-06-27 00:10:57 +00:00
|
|
|
|
This `hello` route has two dynamic parameters, identified with angle brackets,
|
|
|
|
|
declared in the route URI: `<name>` and `<age>`. Rocket maps each parameter to
|
|
|
|
|
an identically named function argument: `name: &str` and `age: u8`. The dynamic
|
|
|
|
|
data in the incoming request is parsed automatically into a value of the
|
|
|
|
|
argument's type. The route is called only when parsing succeeds.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
2021-06-27 00:10:57 +00:00
|
|
|
|
Parsing is directed by the
|
|
|
|
|
[`FromParam`](@api/rocket/request/trait.FromParam.html) trait. Rocket implements
|
|
|
|
|
`FromParam` for many standard types, including both `&str` and `u8`. You can
|
|
|
|
|
implement it for your own types, too!
|
2017-04-17 02:48:59 +00:00
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
[[panels]]
|
|
|
|
|
name = "Handling Data"
|
|
|
|
|
content = '''
|
2021-06-27 00:10:57 +00:00
|
|
|
|
Rocket can automatically parse body data, too!
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
|
|
```rust
|
2021-06-27 00:10:57 +00:00
|
|
|
|
#[post("/login", data = "<login>")]
|
|
|
|
|
fn login(login: Form<UserLogin>) -> String {
|
|
|
|
|
format!("Hello, {}!", login.name)
|
2017-04-17 02:48:59 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2021-06-27 00:10:57 +00:00
|
|
|
|
The dynamic parameter declared in the `data` route attribute parameter again
|
|
|
|
|
maps to a function argument. Here, `login` maps to `login: Form<UserLogin>`.
|
|
|
|
|
Parsing is again trait-directed, this time by the
|
|
|
|
|
[`FromData`](@api/rocket/data/trait.FromData.html) trait.
|
|
|
|
|
|
|
|
|
|
The [`Form`](@api/rocket/form/struct.Form.html) type is Rocket's [robust form
|
|
|
|
|
data parser](@guide/requests/#forms). It automatically parses the request body into the internal type,
|
|
|
|
|
here `UserLogin`. Other built-in `FromData` types include
|
|
|
|
|
[`Data`](@api/rocket/struct.Data.html),
|
2021-05-25 01:58:05 +00:00
|
|
|
|
[`Json`](@api/rocket/serde/json/struct.Json.html), and
|
2021-06-27 00:10:57 +00:00
|
|
|
|
[`MsgPack`](@api/rocket/serde/msgpack/struct.MsgPack.html). As always, you can
|
|
|
|
|
implement `FromData` for your own types, too!
|
2017-04-17 02:48:59 +00:00
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
[[panels]]
|
|
|
|
|
name = "Request Guards"
|
|
|
|
|
content = '''
|
|
|
|
|
In addition to dynamic path and data parameters, request handlers can also
|
|
|
|
|
contain a third type of parameter: _request guards_. Request guards aren't
|
|
|
|
|
declared in the route attribute, and any number of them can appear in the
|
|
|
|
|
request handler signature.
|
|
|
|
|
|
|
|
|
|
Request guards _protect_ the handler from running unless some set of conditions
|
|
|
|
|
are met by the incoming request metadata. For instance, if you are writing an
|
|
|
|
|
API that requires sensitive calls to be accompanied by an API key in the request
|
2017-07-12 21:53:08 +00:00
|
|
|
|
header, Rocket can protect those calls via a custom `ApiKey` request guard:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
#[get("/sensitive")]
|
2018-11-07 07:35:03 +00:00
|
|
|
|
fn sensitive(key: ApiKey) { ... }
|
2017-04-17 02:48:59 +00:00
|
|
|
|
```
|
|
|
|
|
|
2017-07-12 21:53:08 +00:00
|
|
|
|
`ApiKey` protects the `sensitive` handler from running incorrectly. In order for
|
|
|
|
|
Rocket to call the `sensitive` handler, the `ApiKey` type needs to be derived
|
2018-11-07 07:35:03 +00:00
|
|
|
|
through a [`FromRequest`](@api/rocket/request/trait.FromRequest.html)
|
2017-04-17 02:48:59 +00:00
|
|
|
|
implementation, which in this case, validates the API key header. Request guards
|
|
|
|
|
are a powerful and unique Rocket concept; they centralize application policy and
|
|
|
|
|
invariants through types.
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
[[panels]]
|
|
|
|
|
name = "Responders"
|
|
|
|
|
content = '''
|
2017-08-29 17:32:13 +00:00
|
|
|
|
The return type of a request handler can be any type that implements
|
2021-06-27 00:10:57 +00:00
|
|
|
|
[`Responder`](@api/rocket/response/trait.Responder.html):
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
#[get("/")]
|
|
|
|
|
fn route() -> T { ... }
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Above, T must implement `Responder`. Rocket implements `Responder` for many of
|
|
|
|
|
the standard library types including `&str`, `String`, `File`, `Option`, and
|
|
|
|
|
`Result`. Rocket also implements custom responders such as
|
2021-06-27 00:10:57 +00:00
|
|
|
|
[`Redirect`](@api/rocket/response/struct.Redirect.html),
|
|
|
|
|
[`Flash`](@api/rocket/response/struct.Flash.html), and
|
|
|
|
|
[`Template`](@api/rocket_dyn_templates/struct.Template.html).
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
2017-08-18 23:46:13 +00:00
|
|
|
|
The task of a `Responder` is to generate a
|
2018-10-16 06:24:23 +00:00
|
|
|
|
[`Response`](@api/rocket/response/struct.Response.html), if possible.
|
|
|
|
|
`Responder`s can fail with a status code. When they do, Rocket calls the
|
|
|
|
|
corresponding error catcher, a `catch` route, which can be declared as follows:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
|
|
```rust
|
2017-09-23 02:04:14 +00:00
|
|
|
|
#[catch(404)]
|
2017-04-17 02:48:59 +00:00
|
|
|
|
fn not_found() -> T { ... }
|
|
|
|
|
```
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
[[panels]]
|
|
|
|
|
name = "Launching"
|
|
|
|
|
content = '''
|
2021-06-27 00:10:57 +00:00
|
|
|
|
Finally, we get to launch our application! Rocket begins dispatching requests to
|
|
|
|
|
routes after they've been _mounted_ and the application has been _launched_.
|
|
|
|
|
These two steps, usually wrtten in a `rocket` function, look like:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
|
|
```rust
|
2020-06-16 12:01:26 +00:00
|
|
|
|
#[launch]
|
2021-04-14 04:59:11 +00:00
|
|
|
|
fn rocket() -> _ {
|
2021-04-08 08:07:52 +00:00
|
|
|
|
rocket::build().mount("/base", routes![index, another])
|
2020-06-16 12:01:26 +00:00
|
|
|
|
}
|
2017-04-17 02:48:59 +00:00
|
|
|
|
```
|
|
|
|
|
|
2021-06-27 00:10:57 +00:00
|
|
|
|
The `mount` call takes a _base_ and a set of routes via the `routes!` macro. The
|
|
|
|
|
base path (`/base` above) is prepended to the path of every route in the list,
|
|
|
|
|
effectively namespacing the routes. `#[launch]` creates a `main` function that
|
|
|
|
|
starts the server. In development, Rocket prints useful information to the
|
|
|
|
|
console to let you know everything is okay.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
|
|
```sh
|
2021-06-27 00:10:57 +00:00
|
|
|
|
🚀 Rocket has launched from http://127.0.0.1:8000
|
2017-04-17 02:48:59 +00:00
|
|
|
|
```
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
# Steps to "How Rocket Works"
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
[[steps]]
|
|
|
|
|
name = "Validation"
|
|
|
|
|
color = "blue"
|
|
|
|
|
content = '''
|
|
|
|
|
First, Rocket validates a matching request by ensuring that all of the types in
|
|
|
|
|
a given handler can be derived from the incoming request. If the types cannot be
|
|
|
|
|
derived, the request is forwarded to the next matching route until a route’s
|
|
|
|
|
types validate or there are no more routes to try. If all routes fail, a
|
|
|
|
|
customizable **404** error is returned.
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
#[post("/user", data = "<new_user>")]
|
|
|
|
|
fn new_user(admin: AdminUser, new_user: Form<User>) -> T {
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
For the `new_user` handler above to be called, the following conditions must
|
|
|
|
|
hold:
|
|
|
|
|
|
2018-10-22 21:47:35 +00:00
|
|
|
|
* The request method must be `POST`.
|
|
|
|
|
* The request path must be `/user`.
|
|
|
|
|
* The request must contain `data` in its body.
|
|
|
|
|
* The request metadata must authenticate an `AdminUser`.
|
|
|
|
|
* The request body must be a form that parses into a `User` struct.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
[[steps]]
|
|
|
|
|
name = "Processing"
|
|
|
|
|
color = "purple"
|
|
|
|
|
content = '''
|
|
|
|
|
Next, the request is processed by an arbitrary handler. This is where most of
|
|
|
|
|
the business logic in an application resides, and the part of your applications
|
|
|
|
|
you’ll likely spend the most time writing. In Rocket, handlers are simply
|
|
|
|
|
functions - that’s it! The only caveat is that the function’s return type must
|
|
|
|
|
implement the `Responder` trait. The `new_user` function above is an example of
|
|
|
|
|
a handler.
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
[[steps]]
|
|
|
|
|
name = "Response"
|
|
|
|
|
color = "red"
|
|
|
|
|
content = '''
|
|
|
|
|
Finally, Rocket responds to the client by transforming the return value of the
|
|
|
|
|
handler into an HTTP response. The HTTP response generated from the returned
|
|
|
|
|
value depends on the type’s specific `Responder` trait implementation.
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn route() -> T { ... }
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If the function above is used as a handler, for instance, then the type `T` must
|
|
|
|
|
implement `Responder`. Rocket provides many useful responder types out of the
|
|
|
|
|
box. They include:
|
|
|
|
|
|
2018-10-22 21:47:35 +00:00
|
|
|
|
* `Json<T>`: Serializes the structure T into JSON and returns it to
|
|
|
|
|
the client.
|
|
|
|
|
* `Template`: Renders a template file and returns it to the client.
|
|
|
|
|
* `Redirect`: Returns a properly formatted HTTP redirect.
|
|
|
|
|
* `NamedFile`: Streams a given file to the client with the
|
|
|
|
|
Content-Type taken from the file’s extension.
|
|
|
|
|
* `Stream`: Streams data to the client from an arbitrary `Read` value.
|
|
|
|
|
* Many Primitive Types: `String`, `&str`, `File`, `Option`, `Result`, and
|
|
|
|
|
others all implement the `Responder` trait.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
'''
|