mirror of
https://github.com/rwf2/Rocket.git
synced 2024-12-26 04:12:40 +00:00
230 lines
8.1 KiB
TOML
230 lines
8.1 KiB
TOML
###############################################################################
|
||
# 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 `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.
|
||
'''
|
||
|
||
[[panels]]
|
||
name = "Dynamic Params"
|
||
content = '''
|
||
Rocket automatically parses dynamic data in path segments into any desired type.
|
||
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)
|
||
}
|
||
```
|
||
|
||
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.
|
||
|
||
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!
|
||
'''
|
||
|
||
[[panels]]
|
||
name = "Handling Data"
|
||
content = '''
|
||
Rocket can automatically parse body data, too!
|
||
|
||
```rust
|
||
#[post("/login", data = "<login>")]
|
||
fn login(login: Form<UserLogin>) -> String {
|
||
format!("Hello, {}!", login.name)
|
||
}
|
||
```
|
||
|
||
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),
|
||
[`Json`](@api/rocket/serde/json/struct.Json.html), and
|
||
[`MsgPack`](@api/rocket/serde/msgpack/struct.MsgPack.html). As always, you can
|
||
implement `FromData` for your own types, too!
|
||
'''
|
||
|
||
[[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
|
||
header, Rocket can protect those calls via a custom `ApiKey` request guard:
|
||
|
||
```rust
|
||
#[get("/sensitive")]
|
||
fn sensitive(key: ApiKey) { ... }
|
||
```
|
||
|
||
`ApiKey` protects the `sensitive` handler from running incorrectly. In order for
|
||
Rocket to call the `sensitive` handler, the `ApiKey` type needs to be derived
|
||
through a [`FromRequest`](@api/rocket/request/trait.FromRequest.html)
|
||
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 = '''
|
||
The return type of a request handler can be any type that implements
|
||
[`Responder`](@api/rocket/response/trait.Responder.html):
|
||
|
||
```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
|
||
[`Redirect`](@api/rocket/response/struct.Redirect.html),
|
||
[`Flash`](@api/rocket/response/struct.Flash.html), and
|
||
[`Template`](@api/rocket_dyn_templates/struct.Template.html).
|
||
|
||
The task of a `Responder` is to generate a
|
||
[`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:
|
||
|
||
```rust
|
||
#[catch(404)]
|
||
fn not_found() -> T { ... }
|
||
```
|
||
'''
|
||
|
||
[[panels]]
|
||
name = "Launching"
|
||
content = '''
|
||
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:
|
||
|
||
```rust
|
||
#[launch]
|
||
fn rocket() -> _ {
|
||
rocket::build().mount("/base", routes![index, another])
|
||
}
|
||
```
|
||
|
||
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.
|
||
|
||
```sh
|
||
🚀 Rocket has launched from http://127.0.0.1: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:
|
||
|
||
* 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.
|
||
'''
|
||
|
||
[[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:
|
||
|
||
* `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.
|
||
'''
|