Rocket - In-memory counter using State



examples/rocket/in-memory-counter/Cargo.toml
[package]
name = "in-memory-counter"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rocket = "0.5.0"
rocket_dyn_templates = { version = "0.1", features = ["tera"] }
serde = "1.0.201"

examples/rocket/in-memory-counter/src/main.rs
#[macro_use]
extern crate rocket;

use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

use serde::Deserialize;

use rocket::{fairing::AdHoc, State};
use rocket_dyn_templates::{context, Template};

struct HitCount {
    count: AtomicUsize,
}

#[derive(Deserialize)]
struct MyConfig {
    title: String,
}

#[get("/")]
fn index(hit_count: &State<HitCount>, config: &State<MyConfig>) -> Template {
    //let current_count = hit_count.count.load(Ordering::Relaxed);
    let current_count = hit_count.count.fetch_add(1, Ordering::Relaxed);

    Template::render(
        "index",
        context! {
            title: &config.title,
            count: current_count,
        },
    )
}

#[catch(404)]
fn not_found() -> Template {
    Template::render(
        "404",
        context! {
            // Currently the title is set in the template
            //title: "404 Not Found"
        },
    )
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![index])
        .attach(Template::fairing())
        .attach(AdHoc::config::<MyConfig>())
        .manage(HitCount {
            count: AtomicUsize::new(0),
        })
        .register("/", catchers![not_found])
}

#[cfg(test)]
mod tests;

examples/rocket/in-memory-counter/src/tests.rs
use rocket::http::Status;
use rocket::local::blocking::Client;

#[test]
fn hello_world() {
    let client = Client::tracked(super::rocket()).unwrap();
    let response = client.get("/").dispatch();

    assert_eq!(response.status(), Status::Ok);
    assert_eq!(
        response.headers().get_one("Content-Type").unwrap(),
        "text/html; charset=utf-8"
    );
    let html = response.into_string().unwrap();
    assert!(html.contains("<title>Rocket with Tera</title>"));
    assert!(html.contains("<h1>Rocket with Tera</h1>"));
}

#[test]
fn page_not_found() {
    let client = Client::tracked(super::rocket()).unwrap();
    let response = client.get("/other").dispatch();

    assert_eq!(response.status(), Status::NotFound);
    assert_eq!(
        response.headers().get_one("Content-Type").unwrap(),
        "text/html; charset=utf-8"
    );
    let html = response.into_string().unwrap();
    //assert_eq!(html, "");
    assert!(html.contains("<title>404 Not Found</title>"));
    assert!(html.contains("<h1>404 Not Found</h1>"));
    assert!(html.contains("<div>Page not found</div>"));
}

examples/rocket/in-memory-counter/Rocket.toml
[default]
title = "Rocket with Tera"

[debug]

[release]

examples/rocket/in-memory-counter/templates/404.html.tera
{% set title = "404 Not Found" %}
{% include "incl/header" %}

    <div>Page not found</div>

{% include "incl/footer" %}

examples/rocket/in-memory-counter/templates/incl/footer.html.tera
</body>
</html>

examples/rocket/in-memory-counter/templates/incl/header.html.tera
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">

  <title>{{ title }}</title>
</head>
<body>
    <h1>{{title}}</h1>

examples/rocket/in-memory-counter/templates/index.html.tera
{% include "incl/header" %}

    <div>
        Welcome to your Rocket project! Counted: {{count}}
    </div>

{% include "incl/footer" %}