A somewhat complete overview.

This commit is contained in:
Sergio Benitez 2016-10-20 04:40:45 -07:00
parent 81f45608a1
commit 79eab0e907
2 changed files with 583 additions and 184 deletions

245
docs/overview-old.md Normal file
View File

@ -0,0 +1,245 @@
# Overview
A quick glance at what makes Rocket special.
# Introduction
This overview is a concise introduction to Rocket. There's also a [full,
detailed guide](guide). If you want to get started immediately, see
[quickstart](guide/quickstart) or the [getting started
guide](guide/getting_started). Otherwise, welcome!
Rocket makes writing web applications easy, fast, and fun. Below is a complete
Rocket application. In fact, it's [one of many](thisexample) complete, runnable
examples in [Rocket's git repository](github). Can you figure out what it does?
```rust
#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate rocket;
#[get("/<name>/<age>")]
fn hello(name: &str, age: u8) -> String {
format!("Hello, {} year old named {}!", age, name)
}
fn main() {
rocket::ignite()
.mount("/hello", routes![hello])
.launch();
}
```
If you were to run this application, your console would show:
```sh
🔧 Configured for development.
=> listening: localhost:8000
=> logging: Normal
=> session key: false
🛰 Mounting '/hello':
=> GET /hello/<name>/<age>
🚀 Rocket has launched from localhost:8000...
```
Here's a quick summary of what it does: first, on lines 7 - 10, it declares the
`hello` route to `GET /<name>/<age>`, which returns a `String` formatted with
`name` and `age` from the dynamic path. Then, in the `main` function, it creates
a new `Rocket` instance, mounts the `hello` route at `"/hello"`, and launches
the application.
That's it! Let's break this down.
We'll start with lines 1 and 2. Rocket depends on the latest version Rust
nightly; it makes extensive use of Rust's code generation facilities through
compiler plugins. Plugins are still experimental, so we have to tell Rust that
we're okay with that by writing `#![feature(plugin)]`. We also have to tell the
compiler to use Rocket's code generation crate during compilation with
`#![plugin(rocket_codegen)]`. Lines 4 and 5 bring `rocket::Rocket` into the
namespace.
# Routes
The fun begins on line 7, where the `hello` route and request handler are
declared.
Rocket applications are composed primarily of request handlers and routes. A
_request handler_ is a function that takes an arbitrary number of arguments and
returns a response. A _route_ is a combination of:
* A set of parameters to match an incoming request against.
* A request handler to process the request and return a response.
The set of parameters to match against includes static paths, dynamic paths,
path segments, forms, query strings, and request format specifiers. Rocket uses
Rust attributes, which look like function decorators in other languages, to make
declaring routes easy. Routes are declares by annotating a function with the set
of parameters to match against. A complete route declaration looks like:
```rust
#[get("/index")]
fn index() -> &str { "Hello, World!" }
```
You can also use `put`, `post`, `delete`, and `patch` in place of `get`.
## Dynamic Paths
The `hello` route declaration beginning on line 7 of our example applications
tells Rocket that the `hello` function will handle HTTP `GET` requests to the
`<name>/<age>` path. The handler uses `name` and `age` from the path to format
and return a `String` to the user. Here are lines 7 - 10 again:
```rust
#[get("/<name>/<age>")]
fn hello(name: &str, age: u8) -> String {
format!("Hello, {} year old named {}!", age, name)
}
```
The `<name>` and `<age>` parts of the path are _dynamic_: the actual values for
these segments won't be known until someone visits a matching URL. For example,
if someone visit `Mike/21`, `<name>` will be `"Mike"`, and `<age>` will be `21`.
If someone else visits `Bob/91`, `<name>` and `<age>` will be `"Bob"` and
`91`, respectively. Rocket automatically parses dynamic path segments and
passes them to the request handler in variables with matching names. This
means that `name` and `age` can be used immediately in the handler - no
parsing, no checking.
But wait: what happens if someone goes to a URL with an `<age>` that isn't a
valid `u8`? In that case, Rocket doesn't call the handler. Instead, it
_forwards_ the request to the next matching route, if any, and ultimately
returns a `404` if all of them fail. If you want to know if the user passed in a
bad `<age>`, simply use a `Result<u8, &str>` or an `Option<u8>` type for `age`
instead. For more details on routing, route collisions, and much more see the
[routing](guide/routing) chapter of the guide.
Oh, one more thing before we move on! Notice how dynamic path parameters can be
of different types? Actually, path parameters can be of _any_ type, as long as
that type implements Rocket's `FromParam` trait. Rocket uses the `FromParam`
implementation to parse and validate the parameter for you automatically. We've
implemented `FromParam` for plenty of types in the standard library. See the
[FromParam](docs) documentation for more.
## Mounting
Now that we understand the `hello` route, let's move on to lines 13 - 14. Before
Rocket dispatches requests to a route, the route needs to be _mounted_. And
before we can mount a route, we need an instance of `Rocket`.
Mounting a route is like namespacing it. Routes can be mounted any number of
times. Mounting happens with the `mount` method on a `Rocket` instance, which
itself is created with the `ignite()` static method. The `mount` method takes a
list of route handlers given inside of the `route!` macro. The `route!` macro
ties Rocket's code generation to your application. If you'd like to learn more
about the `route!` macro, see the [internals guide](guide/internals).
Let's look at lines 13 - 14 again, which we reproduce below:
```rust
rocket::ignite()
.mount(“/hello”, routes![hello])
```
Line 13 creates the new `Rocket` instance, and line 14 mounts the `hello` route
at the `"/hello"` path. This makes the `hello` handler available at
`/hello/<name>/<age>`. Notice how the mounting path is prepended to the route's
path. There's a ton more information about [mounting in the
guide](/guides/mounting).
## Launching
Now that the route is declared and mounted, the application is ready to launch!
To launch an application and have Rocket start listening for and dispatching
requests, simply call `launch` on the Rocket instance where routes are mounted.
This happens on line 14. Here it is again:
```
rocket.launch()
```
Again, running our full example will show the following in the console:
```sh
🛰 Mounting '/hello':
=> GET /hello/<name>/<age>
🚀 Rocket has launched from localhost:8000...
```
If you visit `http://localhost:8000/hello/Mike/21`, you'll see "Hello, 21 year
old named Mike!". If you have the example running, try visiting other valid and
invalid paths and see what happens! This example's complete crate, ready to
`cargo run`, can be found at
[Github](https://github.com/SergioBenitez/Rocket/tree/master/examples/hello_world).
# Requests
There's a lot more we can do with requests. The [requests](guide/requests)
chapter of the guide talks about requests in details. We'll give you a short
overview of some of the more important and useful features here.
## Forms and Queries
Handling forms and query parameters couldn't be easier: declare a form or query
parameter in the route attribute and handler, then ensure that its type
implements (the automatically derivable) `FromForm`.
Form parameters are declared by adding `form = "<param_name>"` to the route
attribute. Say your application is processing a form submission for a new todo
`Task`. The form contains two fields: `complete`, a checkbox, and `description`,
a text field. You can easily handle the form request in Rocket as follows:
```rust
#[derive(FromForm)]
struct Task {
description: String,
complete: bool
}
#[post("/todo", form = "<task>")]
fn new(task: Task) -> String {
...
}
```
If you change your mind and want to use query strings for the form instead,
simple declare `<task>` as a query parameter as follows:
```rust
#[get("/todo?<task>")]
fn new(task: Task) -> String {
...
}
```
If the form request is invalid according to the form's type, the handler doesn't
get called. Just like in path parameters, you can use `Option` or `Result` in
form structure fields to be notified of parsing errors. You can also easily
define your own types to validate forms and queries against. For more details,
see the [forms](guide/forms) and [queries](guide/queries) chapters of the guide.
## Guards
In addition to `FromParam` types, you can include any number of types that
implement the `FromRequest` trait in handler arguments. For example, to
retrieve cookies from a request, you can use a parameter of `&Cookie` type in a
request handler:
```rust
#[get("/hello")]
fn hello(cookies: &Cookies) -> ..
```
## JSON
# Responses
## Responder
## Templates
## JSON
# What's next?

View File

@ -9,9 +9,69 @@ detailed guide](guide). If you want to get started immediately, see
[quickstart](guide/quickstart) or the [getting started [quickstart](guide/quickstart) or the [getting started
guide](guide/getting_started). Otherwise, welcome! guide](guide/getting_started). Otherwise, welcome!
Rocket makes writing web applications easy, fast, and fun. Below is a complete Rocket makes writing web applications easy, fast, and fun. It is Rocket's goal
Rocket application. In fact, it's [one of many](thisexample) complete, runnable to have you write as little code as necessary to accomplish your goal. In
examples in [Rocket's git repository](github). Can you figure out what it does? practice, this means that your code will be free of boilerplate and that the
common tasks will be handled for you.
# Routes and Handlers
Rocket applications are centered around routes and handlers.
A _handler_ is simply a function that takes an arbitrary number of arguments and
returns a response. 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 set of parameters to match against includes 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")]
fn world() -> &'static str {
"Hello, world!"
}
```
This declares the `world` route which matches against the static path
`"/world"` for incoming `GET` requests.
## Mounting
Before Rocket dispatches requests to a route, the route needs to be _mounted_ on
an instance of `Rocket`.
Mounting a route is like namespacing it. Routes are mounted happens 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 `route!` macro. The `route!` macro
ties Rocket's code generation to your application. To mount the `world` route we
declared above, we would use the following code:
```rust
rocket::ignite().mount(“/hello”, routes![world])
```
All together, this creates a new `Rocket` instance via the `ignite` function and
mounts the `world` route to the `"/hello"` path. As a result, requests to the
`"/hello/world"` path will be directed to the `world` function.
## 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.
We typically call `launch` from the `main` function. Our complete _Hello,
world!_ application thus looks like:
```rust ```rust
#![feature(plugin)] #![feature(plugin)]
@ -19,227 +79,321 @@ examples in [Rocket's git repository](github). Can you figure out what it does?
extern crate rocket; extern crate rocket;
#[get("/<name>/<age>")] #[get("/world")]
fn hello(name: &str, age: u8) -> String { fn world() -> &'static str {
format!("Hello, {} year old named {}!", age, name) "Hello, world!"
} }
fn main() { fn main() {
rocket::ignite() rocket::ignite().mount("/hello", routes![world]).launch();
.mount("/hello", routes![hello])
.launch();
} }
``` ```
If you were to run this application, your console would show: 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.
If we were to run the application above, our console would show:
```sh ```sh
🔧 Configured for development. 🔧 Configured for development.
=> listening: localhost:8000 => listening: localhost:8000
=> logging: Normal => logging: Normal
=> session key: false => session key: false
🛰 Mounting '/hello': 🛰 Mounting '/world':
=> GET /hello/<name>/<age> => GET /hello/world
🚀 Rocket has launched from localhost:8000... 🚀 Rocket has launched from localhost:8000...
``` ```
Here's a quick summary of what it does: first, on lines 7 - 10, it declares the If we now visit `localhost:8000/hello/world`, we would see `Hello, world!`,
`hello` route to `GET /<name>/<age>`, which returns a `String` formatted with exactly as we'd expect.
`name` and `age` from the dynamic path. Then, in the `main` function, it creates
a new `Rocket` instance, mounts the `hello` route at `"/hello"`, and launches
the application.
That's it! Let's break this down. By the way, this example's complete crate, ready to `cargo run`, can be found on
We'll start with lines 1 and 2. Rocket depends on the latest version Rust
nightly; it makes extensive use of Rust's code generation facilities through
compiler plugins. Plugins are still experimental, so we have to tell Rust that
we're okay with that by writing `#![feature(plugin)]`. We also have to tell the
compiler to use Rocket's code generation crate during compilation with
`#![plugin(rocket_codegen)]`. Lines 4 and 5 bring `rocket::Rocket` into the
namespace.
# Routes
The fun begins on line 7, where the `hello` route and request handler are
declared.
Rocket applications are composed primarily of request handlers and routes. A
_request handler_ is a function that takes an arbitrary number of arguments and
returns a response. A _route_ is a combination of:
* A set of parameters to match an incoming request against.
* A request handler to process the request and return a response.
The set of parameters to match against includes static paths, dynamic paths,
path segments, forms, query strings, and request format specifiers. Rocket uses
Rust attributes, which look like function decorators in other languages, to make
declaring routes easy. Routes are declares by annotating a function with the set
of parameters to match against. A complete route declaration looks like:
```rust
#[get("/index")]
fn index() -> &str { "Hello, World!" }
```
You can also use `put`, `post`, `delete`, and `patch` in place of `get`.
## Dynamic Paths
The `hello` route declaration beginning on line 7 of our example applications
tells Rocket that the `hello` function will handle HTTP `GET` requests to the
`<name>/<age>` path. The handler uses `name` and `age` from the path to format
and return a `String` to the user. Here are lines 7 - 10 again:
```rust
#[get("/<name>/<age>")]
fn hello(name: &str, age: u8) -> String {
format!("Hello, {} year old named {}!", age, name)
}
```
The `<name>` and `<age>` parts of the path are _dynamic_: the actual values for
these segments won't be known until someone visits a matching URL. For example,
if someone visit `Mike/21`, `<name>` will be `"Mike"`, and `<age>` will be `21`.
If someone else visits `Bob/91`, `<name>` and `<age>` will be `"Bob"` and
`91`, respectively. Rocket automatically parses dynamic path segments and
passes them to the request handler in variables with matching names. This
means that `name` and `age` can be used immediately in the handler - no
parsing, no checking.
But wait: what happens if someone goes to a URL with an `<age>` that isn't a
valid `u8`? In that case, Rocket doesn't call the handler. Instead, it
_forwards_ the request to the next matching route, if any, and ultimately
returns a `404` if all of them fail. If you want to know if the user passed in a
bad `<age>`, simply use a `Result<u8, &str>` or an `Option<u8>` type for `age`
instead. For more details on routing, route collisions, and much more see the
[routing](guide/routing) chapter of the guide.
Oh, one more thing before we move on! Notice how dynamic path parameters can be
of different types? Actually, path parameters can be of _any_ type, as long as
that type implements Rocket's `FromParam` trait. Rocket uses the `FromParam`
implementation to parse and validate the parameter for you automatically. We've
implemented `FromParam` for plenty of types in the standard library. See the
[FromParam](docs) documentation for more.
## Mounting
Now that we understand the `hello` route, let's move on to lines 13 - 14. Before
Rocket dispatches requests to a route, the route needs to be _mounted_. And
before we can mount a route, we need an instance of `Rocket`.
Mounting a route is like namespacing it. Routes can be mounted any number of
times. Mounting happens with the `mount` method on a `Rocket` instance, which
itself is created with the `ignite()` static method. The `mount` method takes a
list of route handlers given inside of the `route!` macro. The `route!` macro
ties Rocket's code generation to your application. If you'd like to learn more
about the `route!` macro, see the [internals guide](guide/internals).
Let's look at lines 13 - 14 again, which we reproduce below:
```rust
rocket::ignite()
.mount(“/hello”, routes![hello])
```
Line 13 creates the new `Rocket` instance, and line 14 mounts the `hello` route
at the `"/hello"` path. This makes the `hello` handler available at
`/hello/<name>/<age>`. Notice how the mounting path is prepended to the route's
path. There's a ton more information about [mounting in the
guide](/guides/mounting).
## Launching
Now that the route is declared and mounted, the application is ready to launch!
To launch an application and have Rocket start listening for and dispatching
requests, simply call `launch` on the Rocket instance where routes are mounted.
This happens on line 14. Here it is again:
```
rocket.launch()
```
Again, running our full example will show the following in the console:
```sh
🛰 Mounting '/hello':
=> GET /hello/<name>/<age>
🚀 Rocket has launched from localhost:8000...
```
If you visit `http://localhost:8000/hello/Mike/21`, you'll see "Hello, 21 year
old named Mike!". If you have the example running, try visiting other valid and
invalid paths and see what happens! This example's complete crate, ready to
`cargo run`, can be found at
[Github](https://github.com/SergioBenitez/Rocket/tree/master/examples/hello_world). [Github](https://github.com/SergioBenitez/Rocket/tree/master/examples/hello_world).
You can find dozens of other complete examples, spanning all of Rocket's
features, in the [Github examples
directory](https://github.com/SergioBenitez/Rocket/tree/master/examples/).
# Requests # Requests
There's a lot more we can do with requests. The [requests](guide/requests) If all we could do was match against static paths like `"/world"`, Rocket
chapter of the guide talks about requests in details. We'll give you a short wouldn't be much fun. Of course, Rocket allows you to match against just about
overview of some of the more important and useful features here. any information in an incoming request.
## Forms and Queries ## Dynamic Paths
Handling forms and query parameters couldn't be easier: declare a form or query You can declare path segments as dynamic by using angle brackets around variable
parameter in the route attribute and handler, then ensure that its type names in a route's path. For example, if we wanted to say _Hello!_ to anything,
implements (the automatically derivable) `FromForm`. not just the world, we could declare a route and handler like so:
Form parameters are declared by adding `form = "<param_name>"` to the route ```rust
attribute. Say your application is processing a form submission for a new todo #[get("/hello/<name>")]
`Task`. The form contains two fields: `complete`, a checkbox, and `description`, fn hello(name: &str) -> String {
a text field. You can easily handle the form request in Rocket as follows: format!("Hello, {}!", name)
}
```
If we were to mount the path at the root (`.mount("/", routes![hello])`), then
any request to a path with two non-empty segments, where the first segment is
`hello`, will be dispatched to the `hello` route. For example, if we were to
visit `/hello/John`, the application would respond with `Hello, John!`.
You can have any number of dynamic path segments, and the type of the path
segment can be any type that implements the [FromParam
trait](https://api.rocket.rs/rocket/request/trait.FromParam.html), including
your own! Here's a somewhat complicated route to illustrate:
```rust
#[get("/hello/<name>/<age>/<cool>")]
fn hello(name: &str, age: u8, cool: bool) -> String {
if cool {
format!("You're a cool {} year old, {}!", age, name)
} else {
format!("{}, we need to talk about your coolness.", name)
}
}
```
## Forwarding
What if `cool` ain't a `bool`? Or, what if `age` isn't a `u8`? In this case, the
request is _forwarded_ to the next matching route, if there is any. This
continues until a route doesn't forward the request or there are no more routes
to try. When there are no remaining matching routes, a 404 error, which is
customizable, is returned.
Routes are tried in increasing _rank_ order. By default, routes with static
paths have a rank of 0 and routes with dynamic paths have a rank of 1. Ranks can
be manually set with the `rank` route parameter.
To illustrate, consider the following two routes:
```rust
#[get("/user/<id>")]
fn user(id: usize) -> T { ... }
```
```rust
#[get("/user/<id>", rank = 2)]
fn user_str(id: &str) -> T { ... }
```
Notice the `rank` parameter in the second route, which sets the rank of the
`user_str` route to 2. If we run this application with both routes mounted at
the root (`.mount("/", routes![user, user_str])`), requests to any route where
the `<id>` path segment is an unsigned integer will be handled by the `user`
route. If the `<id>` path segment is not an unsigned integer, the `user` route
will forward the request. Rocket will then dispatch the request to the next
matching route, `user_str`.
Forwards can be _caught_ by using a `Result` or `Option` type. For example, if
the type of `id` in the `user` function was `Result<usize, &str>`, an `Ok`
variant would indicate that `<id>` was a valid `usize`, while an `Err` would
indicate that `<id>` was not a `usize`. The `Err`'s value would contain the
string that failed to parse as a `usize`.
By the way, if you were to omit the `rank` parameter in the `user_str` route,
Rocket would emit a warning indicating that the `user` and `user_str` routes
_collide_, or can both match against an incoming request. The `rank` parameter
resolves this collision.
## Request Guards
Sometimes we need data associated with a request that isn't a direct input.
Headers and cookies are a good example of this: they simply tag along for the
ride.
Rocket makes retrieving such information easy: simply add any number of
parameters to the request handler with types that implement the `FromRequest`
trait. If the data can be retrieved from the incoming request, the handler is
called. If it cannot, the handler isn't called, and the request is forwarded on.
In this way, these parameters also act as _guards_: they protect the request
handler from being called erroneously.
For example, to retrieve cookies and the Content-Type header from a request, we
can declare a route as follows:
```rust
#[get("/")]
fn index(cookies: &Cookies, content: ContentType) -> String { ... }
```
You can implement `FromRequest` for your own types as well. For example, you
might implement `FromRequest` for an `AdminUser` type that validates that the
cookies in the incoming request authenticate an administrator. Then, any handler
with the `AdminUser` type in its argument list is assured that it will only be
invoked if an administrative user is logged in. This centralizes policies,
resulting in a simpler, safer, and more secure application.
## Data
At some point, your web application will need to process data, and Rocket makes
it as simple as possible. Data processing, like much of Rocket, is type
directed. To indicate that a handler expects data, annotate a route with a `data
= "<param>"` parameter, where `param` is an argument in the handler of a type
that implement the `FromData` trait.
### Forms
Forms are the most common type of data handled in web applications, and Rocket
makes handling them easy. Say your application is processing a form submission
for a new todo `Task`. The form contains two fields: `complete`, a checkbox, and
`description`, a text field. You can easily handle the form request in Rocket
as follows:
```rust ```rust
#[derive(FromForm)] #[derive(FromForm)]
struct Task {
complete: bool,
description: String,
}
#[post("/todo", data = "<task>")]
fn new(task: Form<Task>) -> String { ... }
```
The `Form` type implements the `FromData` trait as long as its generic parameter
implements the `FromForm` trait. In the example, we've derived the `FromForm`
trait automatically for the `Task` structure. If a `POST /todo` request arrives,
the form data will automatically be parsed into the `Task` structure. If the
data that arrives isn't of the correct content-type, the request is forwarded.
If the data is simply invalid, a customizable `400 Bad Request` error is
returned. As before, a forward or failure can be caught by using the `Option`
and `Result` types.
### Query Strings
If you change your mind and decide to use query strings instead of `POST` forms
for the todo task, Rocket makes the transition simple: simply declare `<task>`
as a query parameter as follows:
```rust
#[get("/todo?<task>")]
fn new(task: Task) -> String { ... }
```
This works because Rocket uses the `FromForm` trait to parse structures from
query parameters as well.
### JSON
Handling JSON data is no harder: simply use the `JSON` type:
```rust
#[derive(Deserialize)]
struct Task { struct Task {
description: String, description: String,
complete: bool complete: bool
} }
#[post("/todo", form = "<task>")] #[post("/todo", data = "<task>")]
fn new(task: Task) -> String { fn new(task: JSON<Task>) -> String { ... }
... ```
The only condition is that the generic type to `JSON` implements the
`Deserialize` trait.
### Streaming Data
Sometimes you just want to handle the incoming data directly. For example, you
might want to stream the incoming data out to a file. Rocket makes this as
simple as possible:
```rust
#[post("/upload", format = "text/plain", data = "<data>")]
fn upload(data: Data) -> io::Result<Plain<String>> {
data.stream_to_file("/tmp/upload.txt").map(|n| Plain(n.to_string()))
} }
``` ```
If you change your mind and want to use query strings for the form instead, The route above accepts any `POST` request to the `/upload` path with
simple declare `<task>` as a query parameter as follows: `Content-Type` `text/plain` The incoming data is streamed out to
`tmp/upload.txt` file, and the number of bytes written is returned as a plain
```rust text response if the upload succeeds. If the upload fails, an error response is
#[get("/todo?<task>")] returned. The handler above is complete. It really is that simple! See the
fn new(task: Task) -> String { [Github example
... code](https://github.com/SergioBenitez/Rocket/blob/master/examples/raw_upload/src/main.rs)
} for the full crate.
```
If the form request is invalid according to the form's type, the handler doesn't
get called. Just like in path parameters, you can use `Option` or `Result` in
form structure fields to be notified of parsing errors. You can also easily
define your own types to validate forms and queries against. For more details,
see the [forms](guide/forms) and [queries](guide/queries) chapters of the guide.
## Guards
In addition to `FromParam` types, you can include any number of types that
implement the `FromRequest` trait in handler arguments. For example, to
retrieve cookies from a request, you can use a parameter of `&Cookie` type in a
request handler:
```rust
#[get("/hello")]
fn hello(cookies: &Cookies) -> ..
```
## JSON
# Responses # Responses
## Responder Up until the last example, we've been returning the type of `String` from
request handlers. In fact, any type that implements the `Responder` trait can be
returned, including your own!
## Templates ## Result
One of the most common types to return is `Result`. Returning a `Result` means
one of two things: If the error type tself implements `Responder`, the response
will come from either the `Ok` or `Err` value, whichever the variant is. If the
error type does _not_ implement `Responder`, a customizable internal server
error will be returned.
## JSON ## JSON
Responding with JSON data is just as simple: simply return a JSON type. For
example, to respond with the JSON value of the `Task` structure from previous
examples, we would write:
```rust
#[derive(Serialize)]
struct Task { ... }
#[get("/todo")]
fn todo() -> JSON<Task> { ... }
```
Note that the generic type for the JSON response type must implement
`Serialize`.
## Templates
Rocket has built-in support for templating. To respond with a rendered template,
simply return a `Template` type:
```rust
#[get("/")]
fn index() -> Template {
let context = ...;
Template::render("index", &context)
}
```
The `render` static method takes in the name of a template (here, `"index"`) and
a value to use as the _context_ for the template's rendering. The context must
contain all of the parameters expected by the template.
Templating support in Rocket is engine agnostic. The engine used to render a
template depends on the template file's extension. For example, if a file ends
with `.hbs`, Handlebars is used, while if a file ends with `.tera`, Tera is
used.
## Streaming
When a large amount of data is to be returned, it is often better to stream the
data to the client so as to avoid consuming large amounts of memory. Rocket
provides the `Stream` type to accomplish this. The `Stream` type can be created
from any `Read` type. For example, to stream from a local Unix stream, we might
write:
```rust
#[get("/stream")]
fn stream() -> io::Result<Stream<UnixStream>> {
let mut unix = UnixStream::connect("/path/to/my/socket")?;
Stream::from(unix)
}
```
Rocket takes care of the rest.
# What's next? # What's next?
That was just a taste of what Rocket has to offer! There's so much more:
* [Quickstart](guide/quickstart): How to get started as quickly as possible.
* [Getting Started](guide/getting_started): How to start your first project.
* [Overview](overview): A brief introduction.
* [Guide](guide): A detailed guide and reference to every component.
* [API Documentation](https://api.rocket.rs): The "rustdocs" (API documentation).