#[macro_use] extern crate actix_web; #[macro_use] extern crate serde_json; use actix_http::{body::Body, Response}; use actix_web::dev::ServiceResponse; use actix_web::http::StatusCode; use actix_web::middleware::errhandlers::{ErrorHandlerResponse, ErrorHandlers}; use actix_web::{web, App, HttpResponse, HttpServer, Result}; use handlebars::Handlebars; use std::io; // Macro documentation can be found in the actix_web_codegen crate #[get("/")] async fn index(hb: web::Data>) -> HttpResponse { let data = json!({ "name": "Handlebars" }); let body = hb.render("index", &data).unwrap(); HttpResponse::Ok().body(body) } #[get("/{user}/{data}")] async fn user( hb: web::Data>, info: web::Path<(String, String)>, ) -> HttpResponse { let data = json!({ "user": info.0, "data": info.1 }); let body = hb.render("user", &data).unwrap(); HttpResponse::Ok().body(body) } #[actix_web::main] async fn main() -> io::Result<()> { // Handlebars uses a repository for the compiled templates. This object must be // shared between the application threads, and is therefore passed to the // Application Builder as an atomic reference-counted pointer. let mut handlebars = Handlebars::new(); handlebars .register_templates_directory(".html", "./static/templates") .unwrap(); let handlebars_ref = web::Data::new(handlebars); HttpServer::new(move || { App::new() .wrap(error_handlers()) .app_data(handlebars_ref.clone()) .service(index) .service(user) }) .bind("127.0.0.1:8080")? .run() .await } // Custom error handlers, to return HTML responses when an error occurs. fn error_handlers() -> ErrorHandlers { ErrorHandlers::new().handler(StatusCode::NOT_FOUND, not_found) } // Error handler for a 404 Page not found error. fn not_found(res: ServiceResponse) -> Result> { let response = get_error_response(&res, "Page not found"); Ok(ErrorHandlerResponse::Response( res.into_response(response.into_body()), )) } // Generic error handler. fn get_error_response(res: &ServiceResponse, error: &str) -> Response { let request = res.request(); // Provide a fallback to a simple plain text response in case an error occurs during the // rendering of the error page. let fallback = |e: &str| { Response::build(res.status()) .content_type("text/plain") .body(e.to_string()) }; let hb = request .app_data::>() .map(|t| t.get_ref()); match hb { Some(hb) => { let data = json!({ "error": error, "status_code": res.status().as_str() }); let body = hb.render("error", &data); match body { Ok(body) => Response::build(res.status()) .content_type("text/html") .body(body), Err(_) => fallback(error), } } None => fallback(error), } }