2. WHO AM I
Denny Biasiolli
Full Stack Developer
(JavaScript, Python, Go, Rust)
Front End Developer UX/ UI
Fingerprint Compliance Services Ltd
Italy, Savigliano (CN)
@dennybiasiolli
denny.biasiolli@gmail.com
www.dennybiasiolli.com
2
10. ROCKET AIMS TO BE FUN
By ensuring that you write as little code
as possible to accomplish your task.
Allows you to focus on the fun parts of
writing web applications.
10
11. ROCKET CORE PHILOSOPHIES
Security, correctness, and developer experience
are paramount.
The path of least resistance should lead you to the most secure, correct web application,
though security and correctness should not come at the cost of a degraded developer
experience.
Rocket is easy to use while taking great measures to ensure that your application is secure
and correct without cognitive overhead.
11
12. ROCKET CORE PHILOSOPHIES
All request handling information
should be typed and self-contained.
Because the web and HTTP are themselves untyped (or stringly typed, as some call it), this
means that something or someone has to convert strings to native types.
Rocket does this for you with zero programming overhead.
What's more, Rocket's request handling is self-contained with zero global state: handlers
are regular functions with regular arguments.
12
13. ROCKET CORE PHILOSOPHIES
Decisions should not be forced.
Templates, serialization, sessions, and just about everything else are all pluggable, optional
components.
While Rocket has official support and libraries for each of these, they are completely
optional and swappable.
13
18. HELLO, WORLD!
> cargo run
🔧 Configured for debug.
>> address: 127.0.0.1
>> port: 8000
>> workers: [..]
>> keep-alive: 5s
>> limits: [..]
>> tls: disabled
>> temp dir: /tmp
>> log level: normal
>> cli colors: true
🛰 Routes:
>> (index) GET /
🚀 Rocket has launched from http://127.0.0.1:8000
18
19. But wait, what's this?
Error: Rocket failed to bind network socket to
given address/port.
>> Address already in use (os error 48)
19
20. Rocket.toml FILE
## defaults for all profiles
[default]
port = 8000
## set only when compiled in debug mode,
## i.e, `cargo build` or `cargo run`
[debug]
port = 8001
https://rocket.rs/guide/v0.5/configuration/
20
21. Rocket.toml FILE
## set only when the `custom-profile` profile is selected,
## i.e, `ROCKET_PROFILE=custom-profile cargo build --release`
[custom-profile]
port = 9001
## set only when compiled in release mode,
## i.e, `cargo build --release`
[release]
port = 9999
https://rocket.rs/guide/v0.5/configuration/
21
22. ENVIRONMENT VARIABLES
Take precedence over Rocket.toml file.
Even at runtime.
ROCKET_PORT=8007 cargo run
https://rocket.rs/guide/v0.5/configuration/
22
26. ROCKET LIFECYCLE
3. Processing
#[get("/hello/<name>")]
fn hello(name: &str, age: u8) -> String {
/**
* Processing
* i.e, checking the age range, etc.
* This is the main business logic of an application.
* Processing completes by returning a Response.
*/
format!("Hello, {} year old named {}!", age, name)
}
26
29. LAUNCHING
allows you to start the server
is useful when a handle to the Future returned by launch() is desired
or when the return value of launch() is to be inspected.
#[rocket::main]
async fn main() -> Result<(), rocket::Error> {
let _rocket = rocket::build()
.mount("/hello", routes![world])
.launch()
.await?;
Ok(())
}
29
31. DYNAMIC PATHS
Any type, as long as the type implements the
FromParam trait.
#[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
)
}
}
31
33. SERVE STATIC FILES
The easy way
use rocket::fs::FileServer;
// use rocket::fs::{relative, FileServer};
#[launch]
fn rocket() -> _ {
rocket::build()
// serve files from `/www/static` at path `/public`
.mount("/public", FileServer::from("/www/static"))
// or `relative!("static")` for a local directory
}
33
35. HTTP METHODS
What about HTML forms?
Form method="post"
Content-Type: application/x-www-form-urlencoded
First field name="_method"
First field value="<a valid HTTP method>"
<form action="/your/path" method="post">
<input type="hidden" name="_method" value="put" />
<!-- other fields -->
35
40. TEMPLATES
Rocket discovers templates in the configurable
template_dir directory.
Templating support in Rocket is engine agnostic.
The engine used to render a template depends on the
template file's extension.
if a file ends with .hbs, Handlebars is used
if a file ends with .tera, Tera is used
40
41. TERA TEMPLATES
Note: The name of the template does not include its
extension.
For a template file named index.html.tera, call
render("index") and use the name "index" in
templates, i.e, extends "index" or extends
"base" for base.html.tera.
41
42. TERA TEMPLATES
Tera is a template engine inspired by Jinja2 and the Django template language.
https://keats.github.io/tera/
<title>{% block title %}{% endblock title %}</title>
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
42
43. REQUEST GUARDS
Types that implement the FromRequest trait
Used to extract data from the request
Can be used as arguments in request handlers
Protect a handler from being called erroneously
#[get("/<param>")]
fn index(param: isize, a: A, b: B, c: C) { /* ... */ }
// `A`, `B`, and `C` are request guards
https://api.rocket.rs/v0.5/rocket/request/trait.FromRequest
43
48. 🍪COOKIES?
use rocket::form::Form;
use rocket::response::Redirect;
use rocket::http::CookieJar;
#[post("/", data = "<message>")]
fn submit(cookies: &CookieJar<'_>, message: Form<&str>) -> Red
cookies.add(("message", message.to_string()));
Redirect::to(uri!(index))
}
#[get("/")]
fn index(cookies: &CookieJar<'_>) -> Option<String> {
cookies.get("message")
.map(|crumb| format!("Message: {}", crumb.value()))
}
48
49. 🍪PRIVATE COOKIES?
1. make sure the "secrets" feature is enabled
2. add "_private" to "add", "get" and "remove"
Encrypted using the 256-bit key specified in the
secret_key configuration parameter.
## in Cargo.toml
rocket = { version = "0.5.0", features = ["secrets
cookies.get_private
cookies.add_private
cookies.remove_private
49
50. FORM INPUT? YES, PLEASE!
Rocket supports both
"multipart" and "x-www-form-urlencoded" forms
out of the box,
enabled by the Form data guard
and derivable FromForm trait.
https://rocket.rs/guide/v0.5/requests/#forms
50
52. FORM INPUT
curl --location 'http://127.0.0.1:8001/todo'
--form 'description="test"'
--form 'complete="true"'
curl --location 'http://127.0.0.1:8001/todo'
--header 'Content-Type: application/x-www-form-urlencoded'
--data-urlencode 'description=test'
--data-urlencode 'complete=true'
# or
# Output form errors with:
# 422 Unprocessable Entity
# or
# 415 Unsupported Media Type
52
53. QUERY PARAMS? YES, PLEASE!
Query strings are URL-encoded forms
that appear in the URL of a request.
Query parameters are declared like path parameters
but otherwise handled like regular URL-encoded form
fields.
https://rocket.rs/guide/v0.5/requests/#query-strings
53
56. JSON INPUT? YES, PLEASE!
Make sure the "json" feature is enabled
The Json<T> guard deserializes body data as JSON.
The only condition is that the generic type T
implements the Deserialize trait from serde.
## in Cargo.toml
rocket = { version = "0.5.0", features = ["json"] }
https://rocket.rs/guide/v0.5/requests/#json
56
63. MANAGED (GLOBAL) STATE
The state is managed on a per-type basis
1. Call manage on the Rocket instance corresponding
to your application with the initial value of the state.
use std::sync::atomic::AtomicUsize;
struct HitCount {
count: AtomicUsize
}
rocket::build()
.manage(HitCount { count: AtomicUsize::new(0) });
63
64. MANAGED (GLOBAL) STATE
2. Add a &State<T> type to any request handler,
where T is the type of the value passed into manage.
use rocket::State;
#[get("/count")]
fn count(hit_count: &State<HitCount>) -> String {
let current_count = hit_count.count.load(Ordering::Rela
format!("Number of visits: {}", current_count)
}
64
65. REQUEST-LOCAL STATE
use rocket::request::{self, Request, FromRequest};
/// A global atomic counter for generating IDs.
static ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
/// A type that represents a request's ID.
struct RequestId(pub usize);
#[get("/")]
fn id(id: &RequestId) -> String {
format!("This is request #{}.", id.0)
}
65
66. REQUEST-LOCAL STATE
/// Returns the current request's ID,
/// assigning one only as necessary.
#[rocket::async_trait]
impl<'r> FromRequest<'r> for &'r RequestId {
type Error = ();
async fn from_request(request: &'r Request<'_>)
-> request::Outcome<Self, Self::Error> {
// The closure passed to `local_cache`
// will be executed at most once per request:
// When requested again, will return the same value.
request::Outcome::Success(request.local_cache(|| {
RequestId(ID_COUNTER.fetch_add(1, Ordering::Relaxe
}))
}
66
67. DATABASES
Rocket includes built-in, ORM-agnostic support for
databases via rocket_db_pools.
The library simplifies accessing one or more databases
via connection pools: data structures that maintain
active database connections for use in the application.
cargo add rocket_db_pools --features "sqlx_sqlite"
# or
cargo add rocket_db_pools --features "sqlx_postgres"
# or
cargo add rocket_db_pools --features "diesel_postgres"
https://api.rocket.rs/v0.5/rocket_db_pools/#supported-drivers
67
68. DATABASES
Configure at least a URL for the database under
databases.$name (in Rocket.toml), where $name is
your choice of database name:
[default.databases.custom_name]
url = "database.sqlite"
[default.databases.custom_name_postgres]
url = "postgresql://[user[:password]@][host][:port][/dbname]"
68