I'm studying rust
/actix
/tera
and cannot figure out how to implement ResponseError
trait on the tera::Error
, or alternatively how to convert tera::Error
to actix_web::Error
.
With the following code snippet:
match TEMPLATES.render("index.html", &ctx) {
Ok(s) => Ok(HttpResponse::Ok().body(s)),
Err(e) => Err(e),
}
I'm getting an error:
mismatched types
expected struct `actix_web::Error`, found struct `tera::Error`rustc(E0308)
main.rs(71, 23): expected struct `actix_web::Error`, found struct `tera::Error`
So I tried the following:
match TEMPLATES.render("index.html", &ctx) {
Ok(s) => Ok(HttpResponse::Ok().body(s)),
Err(e) => Err(e.into()),
}
But in this case I get:
the trait bound `tera::Error: actix_web::ResponseError` is not satisfied
the trait `actix_web::ResponseError` is not implemented for `tera::Error`
note: required because of the requirements on the impl of `std::convert::From<tera::Error>` for `actix_web::Error`
note: required because of the requirements on the impl of `std::convert::Into<actix_web::Error>` for `tera::Error`rustc(E0277)
main.rs(71, 25): the trait `actix_web::ResponseError` is not implemented for `tera::Error`
So finally I've tried:
use actix_web::{get, post, web, error, Error, ResponseError,
HttpRequest, HttpResponse, HttpServer,
App, Responder};
use tera::{Tera, Context};
use tera;
impl ResponseError for tera::Error {}
But now getting:
only traits defined in the current crate can be implemented for arbitrary types
impl doesn't use only types from inside the current crate
note: define and implement a trait or new type insteadrustc(E0117)
main.rs(12, 1): impl doesn't use only types from inside the current crate
main.rs(12, 24): `tera::Error` is not defined in the current crate
Function signature in which I have the match
block is the following:
#[get("/")]
async fn tst() -> Result<HttpResponse, Error> {}
What am I doing wrong?
As you have already discovered, into()
cannot be used to convert the tera::Error
to an actix_web::Error
because no such conversion is directly defined. In this case it gives you a slightly misleading error - because this conversion exists:
impl<T> From<T> for Error
where
T: 'static + ResponseError,
The compiler throws an error saying that if only the tera error implemented ResponseError
, it could do the conversion. But you cannot make it implement that trait, because of the 'trait orphan rule', which says that you cannot implement a trait from outside your own crate onto a type from outside your own crate.
You could wrap the tera::Error
in your own struct, and then implement ResponseError
for that, as outlined in this question.
But there is a simpler solution: actix-web provides a whole swathe of helper functions for converting errors, which you can use like so:
match TEMPLATES.render("index.html", &ctx) {
Ok(s) => Ok(HttpResponse::Ok().body(s)),
Err(e) => Err(error::ErrorInternalServerError(e)),
}
The provided helpers map the supplied error into the named HTTP response code, so you can pick one that most closely represents the error that occurred.
See also the actix-web documentation for error handling.
Caveat Emptor: this solution is untested and I have never used tera
nor actix-web
, rather I gleaned this from skimming their documentation.