axum_htmx/responders/
vary.rs1use axum_core::response::{IntoResponseParts, ResponseParts};
2use http::header::{HeaderValue, VARY};
3
4use crate::{HxError, extractors, headers};
5
6const HX_REQUEST: HeaderValue = HeaderValue::from_static(headers::HX_REQUEST_STR);
7const HX_TARGET: HeaderValue = HeaderValue::from_static(headers::HX_TARGET_STR);
8const HX_TRIGGER: HeaderValue = HeaderValue::from_static(headers::HX_TRIGGER_STR);
9const HX_TRIGGER_NAME: HeaderValue = HeaderValue::from_static(headers::HX_TRIGGER_NAME_STR);
10
11#[derive(Debug, Clone)]
25pub struct VaryHxRequest;
26
27impl IntoResponseParts for VaryHxRequest {
28 type Error = HxError;
29
30 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
31 res.headers_mut().try_append(VARY, HX_REQUEST)?;
32
33 Ok(res)
34 }
35}
36
37impl extractors::HxRequest {
38 pub fn vary_response() -> VaryHxRequest {
40 VaryHxRequest
41 }
42}
43
44#[derive(Debug, Clone)]
54pub struct VaryHxTarget;
55
56impl IntoResponseParts for VaryHxTarget {
57 type Error = HxError;
58
59 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
60 res.headers_mut().try_append(VARY, HX_TARGET)?;
61
62 Ok(res)
63 }
64}
65
66impl extractors::HxTarget {
67 pub fn vary_response() -> VaryHxTarget {
69 VaryHxTarget
70 }
71}
72
73#[derive(Debug, Clone)]
83pub struct VaryHxTrigger;
84
85impl IntoResponseParts for VaryHxTrigger {
86 type Error = HxError;
87
88 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
89 res.headers_mut().try_append(VARY, HX_TRIGGER)?;
90
91 Ok(res)
92 }
93}
94
95impl extractors::HxTrigger {
96 pub fn vary_response() -> VaryHxTrigger {
98 VaryHxTrigger
99 }
100}
101
102#[derive(Debug, Clone)]
112pub struct VaryHxTriggerName;
113
114impl IntoResponseParts for VaryHxTriggerName {
115 type Error = HxError;
116
117 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
118 res.headers_mut().try_append(VARY, HX_TRIGGER_NAME)?;
119
120 Ok(res)
121 }
122}
123
124impl extractors::HxTriggerName {
125 pub fn vary_response() -> VaryHxTriggerName {
127 VaryHxTriggerName
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use std::collections::hash_set::HashSet;
134
135 use axum::{Router, routing::get};
136
137 use super::*;
138
139 #[tokio::test]
140 async fn multiple_headers() {
141 let app = Router::new().route("/", get(|| async { (VaryHxRequest, VaryHxTarget, "foo") }));
142 let server = axum_test::TestServer::new(app).unwrap();
143
144 let resp = server.get("/").await;
145 let values: HashSet<HeaderValue> = resp.iter_headers_by_name("vary").cloned().collect();
146 assert_eq!(values, HashSet::from([HX_REQUEST, HX_TARGET]));
147 }
148}