Rocket: 404 page with static content

Rocket 404 content RawHtml routes! catchers! mount register include_str!

If the user visits a path on our Rocket-based site that does not match any of the routes, by default, Rocket will show a very simple page saying 404: Not Found and The requested resource could not be found..

You might want to have a more fancy page.

In this example you can see how to do that.

Dependencies

We only need Rocket for this.

examples/rocket/http-404-page-with-static-content/Cargo.toml

[package]
name = "http-404-page-with-static-content"
version = "0.1.0"
edition = "2021"

[dependencies]
rocket = "0.5.0"

The HTML

We could embed the HTML in our Rust file, but it is better to have it in a separate file with html extension. That will allow a designer to make it nice without any interaction with Ruts.

Se we have it in a separate file.

Note: I am not a designer.

examples/rocket/http-404-page-with-static-content/src/templates/404.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
  <link href="/css/skeleton.css" rel="stylesheet">
  <script src="/js/skeleton.js"></script>
 
  <title>404 Page not found</title>
</head>
<body>
<h1>Ooups</h1>
This page was not found.
 
</body>
</html>

The main code

examples/rocket/http-404-page-with-static-content/src/main.rs

#[macro_use]
extern crate rocket;

use rocket::response::content;

#[get("/")]
fn index() -> content::RawHtml<&'static str> {
    content::RawHtml("Hello, <b>world!</b>")
}

#[catch(404)]
fn not_found() -> content::RawHtml<&'static str> {
    const BODY: &str = include_str!("templates/404.html");
    content::RawHtml(BODY)
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![index])
        .register("/", catchers![not_found])
}

#[cfg(test)]
mod tests;

The test

examples/rocket/http-404-page-with-static-content/src/tests.rs

use rocket::form::validate::Contains;
use rocket::http::Status;
use rocket::local::blocking::Client;

#[test]
fn main_page() {
    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"
    );
    assert_eq!(response.into_string(), Some("Hello, <b>world!</b>".into()));
}

#[test]
fn page_not_found() {
    let client = Client::tracked(super::rocket()).unwrap();
    let response = client.get("/something").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!(html.contains("<title>404 Page not found</title>"));
    assert!(html.contains("<h1>Ooups</h1>"));
}

Explanation

We implement the function that will be called by Rocket when all routes were tried and none of them matched. It looks exactly like a regular route, but it is marked with catch(404).

#[catch(404)]
fn not_found() -> RawHtml<&'static str> {
    const BODY: &str = include_str!("templates/404.html");
    RawHtml(BODY)
}

The include_str! embeds the external file into the compiled binary during compilation.

We also need to register the catchers using the register method and the catchers! macro:

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![index])
        .register("/", catchers![not_found])
}

In the tests we can verify that the response status for the main route is Ok and for an arbitrary other path is NotFound.

In the main route we checked that the returned page is exactly as we expect.

In the 404 route we demonstrate how to check that some content is in the returned HTML.

Related Pages

Rocket - web development with Rust

Author

Gabor Szabo (szabgab)

Gabor Szabo, the author of the Rust Maven web site maintains several Open source projects in Rust and while he still feels he has tons of new things to learn about Rust he already offers training courses in Rust and still teaches Python, Perl, git, GitHub, GitLab, CI, and testing.

Gabor Szabo