Skip to main content

trillium_handlebars/
handlebars_conn_ext.rs

1use crate::{Assigns, HandlebarsHandler};
2use serde::Serialize;
3use serde_json::json;
4use std::borrow::Cow;
5use trillium::Conn;
6
7/// Extension trait that provides handlebar rendering capabilities to
8/// [`trillium::Conn`]s.
9pub trait HandlebarsConnExt {
10    /// Registers an "assigns" value on this Conn for use in a template.
11    /// See example usage at [`Handlebars::new`](crate::Handlebars::new)
12    fn assign(self, key: impl Into<Cow<'static, str>>, data: impl Serialize) -> Self;
13
14    /// renders a registered template by name with the provided data as
15    /// assigns. note that this does not use any data accumulated by
16    /// [`HandlebarsConnExt::assign`]
17    ///
18    /// ```
19    /// use trillium_handlebars::{Handlebars, HandlebarsConnExt, HandlebarsHandler};
20    /// use trillium_testing::TestServer;
21    ///
22    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
23    ///
24    /// #[derive(serde::Serialize)]
25    /// struct User {
26    ///     name: &'static str,
27    /// };
28    ///
29    /// let mut handlebars = Handlebars::new();
30    /// handlebars.register_template_string("greet-user", "Hello {{name}}")?;
31    ///
32    /// let handler = (
33    ///     HandlebarsHandler::new(handlebars),
34    ///     |mut conn: trillium::Conn| async move {
35    ///         conn.render_with("greet-user", &User { name: "handlebars" })
36    ///     },
37    /// );
38    ///
39    /// # trillium_testing::block_on(async {
40    /// let app = TestServer::new(handler).await;
41    /// app.get("/")
42    ///     .await
43    ///     .assert_ok()
44    ///     .assert_body("Hello handlebars");
45    /// # });
46    /// # Ok(()) }
47    /// ```
48    fn render_with(self, template: &str, data: &impl Serialize) -> Self;
49
50    /// renders a registered template, passing any accumulated assigns to
51    /// the template. See example at [`Handlebars::new`](crate::Handlebars::new)
52    fn render(self, template: &str) -> Self;
53
54    /// retrieves a reference to any accumulated assigns on this conn
55    fn assigns(&self) -> Option<&Assigns>;
56
57    /// retrieves a mutable reference to any accumulated assigns on this
58    /// conn
59    fn assigns_mut(&mut self) -> &mut Assigns;
60}
61
62impl HandlebarsConnExt for Conn {
63    fn render_with(self, template: &str, data: &impl Serialize) -> Self {
64        let handlebars: &HandlebarsHandler = self
65            .state()
66            .expect("HandlebarsConnExt::render called without running the handler first");
67
68        match handlebars.render(template, data) {
69            Ok(string) => self.ok(string),
70            Err(b) => self.with_status(500).with_body(b.to_string()),
71        }
72    }
73
74    fn assign(mut self, key: impl Into<Cow<'static, str>>, data: impl Serialize) -> Self {
75        self.assigns_mut().insert(
76            key.into(),
77            serde_json::to_value(data).expect("could not serialize assigns"),
78        );
79        self
80    }
81
82    fn render(self, template: &str) -> Self {
83        let handlebars: &HandlebarsHandler = self
84            .state()
85            .expect("HandlebarsConnExt::render called without running the handler first");
86
87        let string = if let Some(assigns) = self.assigns() {
88            handlebars.render(template, assigns)
89        } else {
90            handlebars.render(template, &json!({}))
91        };
92
93        match string {
94            Ok(string) => self.ok(string),
95            Err(b) => self.with_status(500).with_body(b.to_string()),
96        }
97    }
98
99    fn assigns(&self) -> Option<&Assigns> {
100        self.state()
101    }
102
103    fn assigns_mut(&mut self) -> &mut Assigns {
104        self.state_entry().or_default()
105    }
106}