Skip to main content

error_page

Function error_page 

Source
pub fn error_page(
    response: Response,
    render: impl FnOnce(&ErrorPage) -> Result<Html<String>>,
) -> Response
Expand description

Renders error responses with the app’s own template (Rails’ public/404.html and 500.html).

Call it from an [axum::middleware::map_response] layer on the app’s router, so every HTML error gets the layout: Errors returned by handlers (their ErrorPage), the 404 of the router’s fallback, and bodyless or plain-text error statuses (axum’s rejections, e.g. a path that does not parse), whose message is the status’s reason phrase. Responses that already have an HTML or JSON body, and success responses, go out unchanged. The status and headers are kept. When render fails, the error is logged and the plain page is sent. Costs a template render per error response, no binding call.

ocre new generates this in src/lib.rs, with templates/error.html:

use askama::Template;
use axum::{Router, middleware::map_response, response::{Html, Response}};
use ocre::{Ctx, Error, ErrorPage, Result, render};

fn routes() -> Router<Ctx> {
    Router::new()
        // ...routes...
        .fallback(not_found)
        .layer(map_response(error_page))
}

async fn not_found() -> Error {
    Error::NotFound
}

#[derive(Template)]
#[template(source = "<h1>{{ error.message }}</h1>", ext = "html")]
struct ErrorView<'a> {
    error: &'a ErrorPage,
}

async fn error_page(response: Response) -> Response {
    ocre::error_page(response, |error| render(&ErrorView { error }))
}

§Examples

use axum::{http::StatusCode, response::{Html, IntoResponse}};
use ocre::Error;

let custom = |error: &ocre::ErrorPage| Ok(Html(format!("<main>{}</main>", error.message)));
let response = ocre::error_page(Error::NotFound.into_response(), custom);
assert_eq!(response.status(), StatusCode::NOT_FOUND);

let rejected = (StatusCode::BAD_REQUEST, "Invalid URL").into_response();
assert_eq!(ocre::error_page(rejected, custom).status(), StatusCode::BAD_REQUEST);