forked from rwf2/Rocket
-
Notifications
You must be signed in to change notification settings - Fork 1
/
overview.toml
229 lines (194 loc) · 8.09 KB
/
overview.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
###############################################################################
# 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.
'''