1
0
mirror of https://github.com/actix/examples synced 2025-02-09 20:25:37 +01:00

138 lines
3.9 KiB
Rust
Raw Normal View History

2022-07-10 03:30:48 +01:00
use std::io;
use actix_web::{
body::BoxBody,
dev::ServiceResponse,
get,
http::{header::ContentType, StatusCode},
middleware::{ErrorHandlerResponse, ErrorHandlers},
web, App, HttpResponse, HttpServer, Responder, Result,
};
use actix_web_lab::{extract::Path, respond::Html};
use fluent_templates::{static_loader, FluentLoader, Loader as _};
2024-03-04 13:05:13 +01:00
use handlebars::{DirectorySourceOptions, Handlebars};
2022-07-10 03:30:48 +01:00
use serde_json::json;
mod lang_choice;
use self::lang_choice::LangChoice;
static_loader! {
static LOCALES = {
locales: "./locales",
fallback_language: "en",
// removes unicode isolating marks around arguments
// you typically should only set to false when testing.
customise: |bundle| bundle.set_use_isolating(false),
};
}
#[get("/")]
async fn index(hb: web::Data<Handlebars<'_>>, lang: LangChoice) -> impl Responder {
let data = json!({ "lang": lang });
let body = hb.render("index", &data).unwrap();
Html(body)
}
#[get("/{user}/{data}")]
async fn user(
hb: web::Data<Handlebars<'_>>,
Path(info): Path<(String, String)>,
lang: LangChoice,
) -> impl Responder {
let data = json!({
"lang": lang,
"user": info.0,
"data": info.1
});
let body = hb.render("user", &data).unwrap();
Html(body)
}
#[actix_web::main]
async fn main() -> io::Result<()> {
2024-03-05 22:30:51 +00:00
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
2022-07-10 03:30:48 +01:00
// Handlebars uses a repository for the compiled templates. This object must be shared between
// the application threads, and is therefore passed to the App in an Arc.
let mut handlebars = Handlebars::new();
// register template dir with Handlebars registry
handlebars
2024-03-04 13:05:13 +01:00
.register_templates_directory(
2024-03-05 22:30:51 +00:00
"./templates",
2024-03-04 13:05:13 +01:00
DirectorySourceOptions {
tpl_extension: ".html".to_owned(),
hidden: false,
temporary: false,
},
)
2022-07-10 03:30:48 +01:00
.unwrap();
// register Fluent helper with Handlebars registry
handlebars.register_helper("fluent", Box::new(FluentLoader::new(&*LOCALES)));
let handlebars = web::Data::new(handlebars);
HttpServer::new(move || {
App::new()
.wrap(error_handlers())
.app_data(web::Data::clone(&handlebars))
.service(index)
.service(user)
})
2024-03-05 22:30:51 +00:00
.workers(2)
2022-07-10 03:30:48 +01:00
.bind(("127.0.0.1", 8080))?
.run()
.await
}
// Custom error handlers, to return HTML responses when an error occurs.
fn error_handlers() -> ErrorHandlers<BoxBody> {
ErrorHandlers::new().handler(StatusCode::NOT_FOUND, not_found)
}
// Error handler for a 404 Page not found error.
fn not_found<B>(res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<BoxBody>> {
let lang = LangChoice::from_req(res.request()).lang_id();
2024-03-04 13:05:13 +01:00
let error = LOCALES.lookup(&lang, "error-not-found");
2022-07-10 03:30:48 +01:00
let response = get_error_response(&res, &error);
Ok(ErrorHandlerResponse::Response(ServiceResponse::new(
res.into_parts().0,
response.map_into_left_body(),
)))
}
// Generic error handler.
fn get_error_response<B>(res: &ServiceResponse<B>, error: &str) -> HttpResponse<BoxBody> {
let req = res.request();
let lang = LangChoice::from_req(req);
// Provide a fallback to a simple plain text response in case an error occurs during the
// rendering of the error page.
let hb = req
.app_data::<web::Data<Handlebars>>()
.expect("correctly set up handlebars in app data");
let data = json!({
"lang": lang,
"error": error,
"status_code": res.status().as_str()
});
let body = hb.render("error", &data);
match body {
Ok(body) => HttpResponse::build(res.status())
.content_type(ContentType::html())
.body(body),
Err(_) => HttpResponse::build(res.status())
.content_type(ContentType::plaintext())
.body(error.to_string()),
}
}