Skip to main content

fhtmx_actix/
response.rs

1use actix_web::{
2    HttpResponse,
3    http::header::{
4        ContentType, Header, HeaderName, HeaderValue, InvalidHeaderValue, TryIntoHeaderValue,
5    },
6};
7use fhtmx::prelude::Render;
8
9/// Renders fhtmx nodes into an Actix [`HttpResponse`].
10pub trait FhtmxActixRender {
11    /// Renders as a `ContentType::html()`
12    fn render_response(&self) -> HttpResponse;
13}
14
15impl<T: Render> FhtmxActixRender for T {
16    fn render_response(&self) -> HttpResponse {
17        let html_body = self.render();
18        HttpResponse::Ok()
19            .content_type(ContentType::html())
20            .body(html_body)
21    }
22}
23
24/// Extractor that checks if the `HX-Request` header is present.
25pub struct HXRequest(bool);
26
27impl HXRequest {
28    /// Whether this request was initiated by htmx.
29    pub fn is_htmx(&self) -> bool {
30        self.0
31    }
32}
33
34impl TryIntoHeaderValue for HXRequest {
35    type Error = InvalidHeaderValue;
36
37    fn try_into_value(self) -> Result<HeaderValue, Self::Error> {
38        HeaderValue::from_str(&self.0.to_string())
39    }
40}
41
42impl Header for HXRequest {
43    fn name() -> HeaderName {
44        HeaderName::from_static("HX-Request")
45    }
46
47    fn parse<M: actix_web::HttpMessage>(msg: &M) -> Result<Self, actix_web::error::ParseError> {
48        let x = msg.headers().contains_key("HX-Request");
49        Ok(Self(x))
50    }
51}