Search code examples
rustactix-webtera

How to display custom Tera errors in Actix?


I'm studying rust/actix/tera and cannot figure out how may I return a custom tera error string in the actix output.

Here's my code:

use actix_web::{App, get, error, Error, HttpResponse, HttpServer};
use tera::{Tera, Context};
use lazy_static::lazy_static;

lazy_static! {
    pub static ref TEMPLATES: Tera = {
        let mut tera = match Tera::new("templates/**/*") {
            Ok(t) => t,
            Err(e) => {
                println!("Template parsing error(s): {}", e);
                ::std::process::exit(1);
            }
        };
        tera.autoescape_on(vec!["html", ".sql"]);
        tera
    };
}

#[get("/")]
async fn tst() -> Result<HttpResponse, Error> {
    let mut ctx = Context::new();
    let title = String::from("Test");
    ctx.insert("title", &title);
    let body = TEMPLATES.render("index.html", &ctx)
        .map_err(|_| error::ErrorInternalServerError("some Tera error here..."))?;
    Ok(HttpResponse::Ok().body(body))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new().service(tst)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Instead of getting the some Tera error here... I would like to return the actual tera error, or better yet, additionally log the error in the stderr output.

[package]
name = "tst"
version = "0.1.0"
edition = "2018"

[dependencies]
actix-web = "3.3.2"
lazy_static = "1.4.0"
tera = "1.12.1"

Solution

  • As it is outlined in this answer, actix-web provides a whole swathe of helper functions for converting errors, therefore to achieve the desired effect the get("/") handler should be changed like follows:

    #[get("/")]
    async fn tst() -> Result<HttpResponse, Error> {
        let mut ctx = Context::new();
        let title = String::from("Test");
        ctx.insert("title", &title);
        match TEMPLATES.render("index.html", &ctx) {
            Ok(body) => Ok(HttpResponse::Ok().body(body)),
            Err(err) => {
                eprintln!("## Tera error: {}", err);
                Err(error::ErrorInternalServerError(err))
            },
        }
    }
    

    Now a specific tera error string can be seen in the server response and the process stderr:

    > curl -LsD- http://127.0.0.1:8080/
    HTTP/1.1 500 Internal Server Error
    content-length: 29
    content-type: text/plain; charset=utf-8
    date: Sat, 18 Sep 2021 18:28:14 GMT
    
    Failed to render 'index.html'