1
0
mirror of https://github.com/actix/examples synced 2024-11-23 14:31:07 +01:00

reduce minijinja boilerplate

This commit is contained in:
Rob Ede 2022-10-16 21:36:23 +01:00
parent 8a22559cac
commit bf0386ade7
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
5 changed files with 62 additions and 35 deletions

1
Cargo.lock generated
View File

@ -6242,6 +6242,7 @@ dependencies = [
name = "templating-minijinja" name = "templating-minijinja"
version = "1.0.0" version = "1.0.0"
dependencies = [ dependencies = [
"actix-utils",
"actix-web", "actix-web",
"actix-web-lab 0.18.5", "actix-web-lab 0.18.5",
"env_logger 0.9.1", "env_logger 0.9.1",

View File

@ -32,7 +32,7 @@ async fn main() -> std::io::Result<()> {
"/", "/",
web::to(|data: web::Data<usize>| async move { web::to(|data: web::Data<usize>| async move {
assert_eq!(**data, 123); assert_eq!(**data, 123);
HttpResponse::NoContent() HttpResponse::NoContent().finish()
}), }),
) )
}) })

View File

@ -6,6 +6,7 @@ edition = "2021"
[dependencies] [dependencies]
actix-web = "4" actix-web = "4"
actix-web-lab = "0.18" actix-web-lab = "0.18"
actix-utils = "3"
env_logger = "0.9" env_logger = "0.9"
log = "0.4" log = "0.4"

View File

@ -1,39 +1,66 @@
use actix_utils::future::{ready, Ready};
use std::collections::HashMap; use std::collections::HashMap;
use actix_web::{ use actix_web::{
dev::ServiceResponse, dev::{self, ServiceResponse},
error, error,
http::{header::ContentType, StatusCode}, http::{header::ContentType, StatusCode},
middleware::{ErrorHandlerResponse, ErrorHandlers, Logger}, middleware::{ErrorHandlerResponse, ErrorHandlers, Logger},
web, App, Error, HttpResponse, HttpServer, Responder, Result, web, App, FromRequest, HttpRequest, HttpResponse, HttpServer, Responder, Result,
}; };
use actix_web_lab::respond::Html; use actix_web_lab::respond::Html;
async fn index( #[derive(Debug)]
struct MiniJinjaRenderer {
tmpl_env: web::Data<minijinja::Environment<'static>>, tmpl_env: web::Data<minijinja::Environment<'static>>,
}
impl MiniJinjaRenderer {
fn render(
&self,
tmpl: &str,
ctx: impl Into<minijinja::value::Value>,
) -> actix_web::Result<Html> {
self.tmpl_env
.get_template(tmpl)
.map_err(|_| error::ErrorInternalServerError("could not find template"))?
.render(ctx.into())
.map(Html)
.map_err(|err| {
log::error!("{err}");
error::ErrorInternalServerError("template error")
})
}
}
impl FromRequest for MiniJinjaRenderer {
type Error = actix_web::Error;
type Future = Ready<Result<Self, Self::Error>>;
fn from_request(req: &HttpRequest, payload: &mut dev::Payload) -> Self::Future {
let tmpl_env = <web::Data<minijinja::Environment<'static>>>::from_request(req, payload)
.into_inner()
.unwrap();
ready(Ok(Self { tmpl_env }))
}
}
async fn index(
tmpl_env: MiniJinjaRenderer,
query: web::Query<HashMap<String, String>>, query: web::Query<HashMap<String, String>>,
) -> Result<impl Responder, Error> { ) -> actix_web::Result<impl Responder> {
let html = if let Some(name) = query.get("name") { if let Some(name) = query.get("name") {
let tmpl = tmpl_env tmpl_env.render(
.get_template("user.html") "user.html",
.map_err(|_| error::ErrorInternalServerError("Template error"))?; minijinja::context! {
name,
let ctx = minijinja::context! { text => "Welcome!",
name, },
text => "Welcome!", )
};
tmpl.render(ctx)
.map_err(|_| error::ErrorInternalServerError("Template error"))?
} else { } else {
tmpl_env tmpl_env.render("index.html", ())
.get_template("index.html") }
.map_err(|_| error::ErrorInternalServerError("Template error"))?
.render(())
.map_err(|_| error::ErrorInternalServerError("Template error"))?
};
Ok(Html(html))
} }
#[actix_web::main] #[actix_web::main]
@ -75,6 +102,8 @@ fn not_found<B>(svc_res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>>
fn get_error_response<B>(res: &ServiceResponse<B>, error: &str) -> HttpResponse { fn get_error_response<B>(res: &ServiceResponse<B>, error: &str) -> HttpResponse {
let req = res.request(); let req = res.request();
let tmpl_env = MiniJinjaRenderer::extract(req).into_inner().unwrap();
// Provide a fallback to a simple plain text response in case an error occurs during the // Provide a fallback to a simple plain text response in case an error occurs during the
// rendering of the error page. // rendering of the error page.
let fallback = |err: &str| { let fallback = |err: &str| {
@ -88,17 +117,13 @@ fn get_error_response<B>(res: &ServiceResponse<B>, error: &str) -> HttpResponse
status_code => res.status().as_str(), status_code => res.status().as_str(),
}; };
match req match tmpl_env.render("error.html", ctx) {
.app_data::<web::Data<minijinja::Environment>>() Ok(body) => body
.and_then(|tmpl_env| tmpl_env.get_template("error.html").ok())
.and_then(|tmpl| tmpl.render(ctx).ok())
{
Some(body) => Html(body)
.customize() .customize()
.with_status(res.status()) .with_status(res.status())
.respond_to(&req) .respond_to(req)
.map_into_boxed_body(), .map_into_boxed_body(),
None => fallback(error), Err(_) => fallback(error),
} }
} }

View File

@ -6,7 +6,7 @@ use actix_web::{
error, error,
http::{header::ContentType, StatusCode}, http::{header::ContentType, StatusCode},
middleware::{self, ErrorHandlerResponse, ErrorHandlers}, middleware::{self, ErrorHandlerResponse, ErrorHandlers},
web, App, Error, HttpResponse, HttpServer, Result, web, App, Error, HttpResponse, HttpServer, Responder, Result,
}; };
use actix_web_lab::respond::Html; use actix_web_lab::respond::Html;
use tera::Tera; use tera::Tera;
@ -15,7 +15,7 @@ use tera::Tera;
async fn index( async fn index(
tmpl: web::Data<tera::Tera>, tmpl: web::Data<tera::Tera>,
query: web::Query<HashMap<String, String>>, query: web::Query<HashMap<String, String>>,
) -> Result<HttpResponse, Error> { ) -> Result<impl Responder, Error> {
let s = if let Some(name) = query.get("name") { let s = if let Some(name) = query.get("name") {
// submitted form // submitted form
let mut ctx = tera::Context::new(); let mut ctx = tera::Context::new();