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!"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This route, named `index`, will match against incoming HTTP `GET` requests to
|
|
|
|
|
the `/` path, the index. The request handler returns a string. Rocket will use
|
|
|
|
|
the string as the body of a fully formed HTTP response.
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
[[panels]]
|
|
|
|
|
name = "Dynamic Params"
|
|
|
|
|
content = '''
|
|
|
|
|
Rocket allows you to interpret segments of a request path dynamically. To
|
|
|
|
|
illustrate, let's use the following route:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
#[get("/hello/<name>/<age>")]
|
|
|
|
|
fn hello(name: &str, age: u8) -> String {
|
|
|
|
|
format!("Hello, {} year old named {}!", age, name)
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `hello` route above matches two dynamic path segments declared inside
|
|
|
|
|
brackets in the path: `<name>` and `<age>`. _Dynamic_ means that the segment can
|
|
|
|
|
be _any_ value the end-user desires.
|
|
|
|
|
|
|
|
|
|
Each dynamic parameter (`name` and `age`) must have a type, here `&str` and
|
|
|
|
|
`u8`, respectively. Rocket will attempt to parse the string in the parameter's
|
|
|
|
|
position in the path into that type. The route will only be called if parsing
|
|
|
|
|
succeeds. To parse the string, Rocket uses the
|
2018-10-16 05:50:35 +00:00
|
|
|
|
[FromParam](@api/rocket/request/trait.FromParam.html) trait,
|
2017-04-17 02:48:59 +00:00
|
|
|
|
which you can implement for your own types!
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
[[panels]]
|
|
|
|
|
name = "Handling Data"
|
|
|
|
|
content = '''
|
|
|
|
|
Request body data is handled in a special way in Rocket: via the
|
2018-10-16 06:24:23 +00:00
|
|
|
|
[FromData](@api/rocket/data/trait.FromData.html) trait. Any type that implements
|
|
|
|
|
`FromData` can be derived from incoming body data. To tell Rocket that you're
|
|
|
|
|
expecting request body data, the `data` route argument is used with the name of
|
|
|
|
|
the parameter in the request handler:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
#[post("/login", data = "<user_form>")]
|
|
|
|
|
fn login(user_form: Form<UserLogin>) -> String {
|
2018-10-22 21:47:35 +00:00
|
|
|
|
format!("Hello, {}!", user_form.name)
|
2017-04-17 02:48:59 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `login` route above says that it expects `data` of type `Form<UserLogin>` in
|
2018-10-16 06:24:23 +00:00
|
|
|
|
the `user_form` parameter. The [Form](@api/rocket/request/struct.Form.html) type
|
|
|
|
|
is a built-in Rocket type that knows how to parse web forms into structures.
|
|
|
|
|
Rocket will automatically attempt to parse the request body into the `Form` and
|
|
|
|
|
call the `login` handler if parsing succeeds. Other built-in `FromData` types
|
|
|
|
|
include [`Data`](@api/rocket/struct.Data.html),
|
|
|
|
|
[`Json`](@api/rocket_contrib/json/struct.Json.html), and
|
|
|
|
|
[`Flash`](@api/rocket/response/struct.Flash.html).
|
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")]
|
2017-07-12 21:53:08 +00:00
|
|
|
|
fn sensitive(key: ApiKey) -> &'static str { ... }
|
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-10-16 06:24:23 +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
|
2018-10-16 05:50:35 +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
|
2018-10-16 05:50:35 +00:00
|
|
|
|
[Redirect](@api/rocket/response/struct.Redirect.html),
|
|
|
|
|
[Flash](@api/rocket/response/struct.Flash.html), and
|
2018-10-16 06:24:23 +00:00
|
|
|
|
[Template](@api/rocket_contrib/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 = '''
|
|
|
|
|
Launching a Rocket application is the funnest part! For Rocket to begin
|
|
|
|
|
dispatching requests to routes, the routes need to be _mounted_. After mounting,
|
|
|
|
|
the application needs to be _launched_. These two steps, usually done in `main`,
|
|
|
|
|
look like:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
rocket::ignite()
|
|
|
|
|
.mount("/base", routes![index, another])
|
2018-10-22 21:47:35 +00:00
|
|
|
|
.launch();
|
2017-04-17 02:48:59 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `mount` call takes a base path 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. This effectively namespaces the routes, allowing for easier composition.
|
|
|
|
|
|
|
|
|
|
The `launch` call starts the server. In development, Rocket prints useful
|
|
|
|
|
information to the console to let you know everything is okay.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
🚀 Rocket has launched from http://localhost:8000...
|
|
|
|
|
```
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
# 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
|
|
|
|
'''
|