I've now been stuck for 3 days trying to get the Askama template engine to render some text that is stored in my database in markdown format. There is not a single example on the internet and yet this template engine gets pushed as excellent.
I've now moved the sql query (I had it before in a handler but I couldn't pass it to Askama) into my async main in order have a shot at passing the data as a state.
// I want to pass this into a handler as a state in order for Askama
// to to render the values inside into a template.
#[derive(Clone)]
struct AppState<'a> {
title: &'a str,
post_body: &'a str,
}
// My SQL query only returns strings so I need this which I then try
// to pass into the struct above this one.
#[derive(FromRow,Debug, Clone)]
struct Post {
title: String,
post_body: String,
}
#[tokio::main]
async fn main() {
let db_connection_str = std::env::var("DATABASE_URL")
.unwrap_or_else(|_| "postgres://postgres:password@localhost/blog_posts".to_string());
let pool = PgPoolOptions::new()
.max_connections(5)
.connect(&db_connection_str)
.await
.expect("can't connect to database");
let my_addr = SocketAddr::from(([127,0,0,1], 3000));
let serve_dir = get_service(ServeDir::new("assets")).handle_error(handle_error);
// I make the SQL query here so that I don't have to call it
// in a handler.
let MYPOST = sqlx::query_as::<_,Post>("select title, post_body from my_posts")
.fetch_all(&pool)
.await
.unwrap();
// I then try to create the state using the query above. It will fail saying that
// the values I pass in don't live long enough.
let shared_state = Arc::new(AppState{pt: &MYPOST[0].title, pb: &MYPOST[0].post_body});
let my_app = Router::new()
.route("/posts", get(blog_handler))
.with_state(shared_state)
.nest_service("/assets", serve_dir.clone())
.fallback_service(serve_dir);
axum::Server::bind(&my_addr)
.serve(my_app.into_make_service())
.await
.unwrap();
}
// I had to place '_ in here to get the compiler to shut up.
// I'm not sure if I'm extracting the values correctly from State<Arc<AppState>>>
// PostTemplate is an Askama Template with the value types being 'a &str
async fn blog_handler(State(state): State<Arc<AppState<'_>>>) -> impl IntoResponse + '_ {
let template = PostTemplate{post_title: &state.title, post_body: &state.post_body};
HtmlTemplate(template)
}
So my issue is that MYPOST
, inside of async main, keeps getting dropped for some unknown
reason and so shared_state
complains about the values not living long enough.
Also Askama's markdown engine doesn't take a String so I have to create an app state using 'a.