Vary headers, closes #14

This commit is contained in:
imbolc 2024-04-30 10:53:00 +06:00
parent ea28c12bb6
commit d0db3a4042
3 changed files with 144 additions and 0 deletions

View file

@ -76,6 +76,25 @@ any of your responses.
| `HX-Trigger-After-Settle` | `HxResponseTrigger` | `axum_htmx::serde::HxEvent` | | `HX-Trigger-After-Settle` | `HxResponseTrigger` | `axum_htmx::serde::HxEvent` |
| `HX-Trigger-After-Swap` | `HxResponseTrigger` | `axum_htmx::serde::HxEvent` | | `HX-Trigger-After-Swap` | `HxResponseTrigger` | `axum_htmx::serde::HxEvent` |
Also, there are corresponding cache-related headers, which you may want to add to
`GET` responses, depending on the htmx headers.
_For example, if your server renders the full HTML when the `HX-Request` header is
missing or `false`, and it renders a fragment of that HTML when `HX-Request: true`,
you need to add `Vary: HX-Request`. That causes the cache to be keyed based on a
composite of the response URL and the `HX-Request` request header - rather than
being based just on the response URL._
Refer to [caching htmx docs section](https://htmx.org/docs/#caching) for details.
| Header | Responder |
|-------------------------|---------------------|
| `Vary: HX-Request` | `VaryHxRequest` |
| `Vary: HX-Target` | `VaryHxTarget` |
| `Vary: HX-Trigger` | `VaryHxTrigger` |
| `Vary: HX-Trigger-Name` | `VaryHxTriggerName` |
## Request Guards ## Request Guards
__Requires features `guards`.__ __Requires features `guards`.__

View file

@ -11,6 +11,8 @@ mod location;
pub use location::*; pub use location::*;
mod trigger; mod trigger;
pub use trigger::*; pub use trigger::*;
mod vary;
pub use vary::*;
const HX_SWAP_INNER_HTML: &str = "innerHTML"; const HX_SWAP_INNER_HTML: &str = "innerHTML";
const HX_SWAP_OUTER_HTML: &str = "outerHTML"; const HX_SWAP_OUTER_HTML: &str = "outerHTML";

123
src/responders/vary.rs Normal file
View file

@ -0,0 +1,123 @@
use axum_core::response::{IntoResponseParts, ResponseParts};
use http::header::VARY;
use crate::{extractors, headers, HxError};
/// The `Vary: HX-Request` header.
///
/// You may want to add this header to the response if your handler responds differently based on
/// the `HX-Request` request header.
///
/// For example, if your server renders the full HTML when the `HX-Request` header is missing or
/// `false`, and it renders a fragment of that HTML when `HX-Request: true`.
///
/// You probably need this only for `GET` requests, as other HTTP methods are not cached by default.
///
/// See <https://htmx.org/docs/#caching> for more information.
#[derive(Debug, Clone)]
pub struct VaryHxRequest;
impl IntoResponseParts for VaryHxRequest {
type Error = HxError;
fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
res.headers_mut()
.insert(VARY, headers::HX_REQUEST.try_into()?);
Ok(res)
}
}
impl extractors::HxRequest {
/// Convenience method to create the corresponding `Vary` response header
pub fn vary_response() -> VaryHxRequest {
VaryHxRequest
}
}
/// The `Vary: HX-Target` header.
///
/// You may want to add this header to the response if your handler responds differently based on
/// the `HX-Target` request header.
///
/// You probably need this only for `GET` requests, as other HTTP methods are not cached by default.
///
/// See <https://htmx.org/docs/#caching> for more information.
#[derive(Debug, Clone)]
pub struct VaryHxTarget;
impl IntoResponseParts for VaryHxTarget {
type Error = HxError;
fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
res.headers_mut()
.insert(VARY, headers::HX_TARGET.try_into()?);
Ok(res)
}
}
impl extractors::HxTarget {
/// Convenience method to create the corresponding `Vary` response header
pub fn vary_response() -> VaryHxTarget {
VaryHxTarget
}
}
/// The `Vary: HX-Trigger` header.
///
/// You may want to add this header to the response if your handler responds differently based on
/// the `HX-Trigger` request header.
///
/// You probably need this only for `GET` requests, as other HTTP methods are not cached by default.
///
/// See <https://htmx.org/docs/#caching> for more information.
#[derive(Debug, Clone)]
pub struct VaryHxTrigger;
impl IntoResponseParts for VaryHxTrigger {
type Error = HxError;
fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
res.headers_mut()
.insert(VARY, headers::HX_TRIGGER.try_into()?);
Ok(res)
}
}
impl extractors::HxTrigger {
/// Convenience method to create the corresponding `Vary` response header
pub fn vary_response() -> VaryHxTrigger {
VaryHxTrigger
}
}
/// The `Vary: HX-Trigger-Name` header.
///
/// You may want to add this header to the response if your handler responds differently based on
/// the `HX-Trigger-Name` request header.
///
/// You probably need this only for `GET` requests, as other HTTP methods are not cached by default.
///
/// See <https://htmx.org/docs/#caching> for more information.
#[derive(Debug, Clone)]
pub struct VaryHxTriggerName;
impl IntoResponseParts for VaryHxTriggerName {
type Error = HxError;
fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
res.headers_mut()
.insert(VARY, headers::HX_TRIGGER_NAME.try_into()?);
Ok(res)
}
}
impl extractors::HxTriggerName {
/// Convenience method to create the corresponding `Vary` response header
pub fn vary_response() -> VaryHxTriggerName {
VaryHxTriggerName
}
}