1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! A lightweight Rust crate for working with HTMX headers, specifically designed to integrate seamlessly with `axum`.
//!
//! HTMX is a library that enhances HTML with AJAX capabilities, and it relies heavily on custom headers to enable
//! dynamic interactions. The `htmxtools` crate simplifies handling these headers in Rust, enabling you to easily
//! extract, process, and respond with HTMX-related data.
//!
//! # Features
//!
//! - **Request Extractors**: Easily extract HTMX headers from incoming requests.
//! - **Response Builders**: Conveniently build responses with HTMX headers.
//! - **Axum Integration**: Built on top of `typed-headers` in `axum-extra` for seamless integration with the `axum`.
//! - **Auto Vary**: Correctly handle response caching by automatically add the `Vary` header to responses based on the
//! extracted HTMX headers.
//!
//! # Usage
//!
//! To use `htmxtools`, run the following command in your project directory:
//!
//! ```bash
//! cargo add htmxtools
//! ```
//!
//! If you don't want to use `axum`, you can still use the `htmxtools` crate with other web frameworks. The crate
//! implements `headers::Header` trait for all HTMX headers, so you can easily extract and build headers in any
//! framework that supports `headers::Header`.
//!
//! To use `htmxtools` without `axum`, run the following command in your project directory:
//!
//! ```bash
//! cargo add htmxtools --no-default-features
//! ```
//!
//! ## Request Extractors
//!
//! To extract HTMX headers from incoming requests in `axum`, you can directly use headers in [`crate::request`] in your
//! handler functions as they implement `FromRequestParts` and `OptionalFromRequestParts` traits.
//!
//! Here's an example of extracting the `hx-request` header:
//!
//! ```rust,no_run
//! use axum_core::response::IntoResponse;
//! use htmxtools::request::HxRequest;
//!
//! async fn handler(hx_request: Option<HxRequest>) -> impl IntoResponse {
//! if hx_request.is_some() {
//! "This is an HTMX request"
//! } else {
//! "This is not an HTMX request"
//! }
//! }
//! ```
//!
//! Here's another example of extracting the `hx-target` header:
//!
//! ```rust,no_run
//! use axum_core::response::IntoResponse;
//! use htmxtools::request::HxTarget;
//!
//! async fn handler(hx_target: HxTarget) -> impl IntoResponse {
//! format!("The target is: {}", hx_target.as_str())
//! }
//!
//! async fn another_handler(hx_target: Option<HxTarget>) -> impl IntoResponse {
//! match hx_target {
//! Some(target) => format!("The target is: {}", target.as_str()),
//! None => "No target specified".to_string(),
//! }
//! }
//! ```
//!
//! ## Response Builders
//!
//! To build responses with HTMX headers in `axum`, you can use headers in [`crate::response`] in your handler functions
//! as they implement `IntoResponseParts` and `IntoResponse` traits.
//!
//! Here's an example of building a response with the `hx-push-url` header:
//!
//! ```rust,no_run
//! use axum_core::response::IntoResponse;
//! use htmxtools::response::HxPushUrl;
//! use http::Uri;
//!
//! async fn handler() -> impl IntoResponse {
//! HxPushUrl::url(Uri::from_static("/new-url"))
//! }
//! ```
//!
//! Here's another example of building a response with `hx-retarget` and `hx-reswap` header:
//!
//! ```rust,no_run
//! use axum_core::response::IntoResponse;
//! use htmxtools::response::{HxReswap, HxRetarget};
//!
//! async fn handler() -> impl IntoResponse {
//! (HxReswap::inner_html(), HxRetarget::from_static("#body"), "<div></div>")
//! }
//! ```
//!
//! ## Auto Vary
//!
//! To automatically add the `Vary` header to responses based on the extracted HTMX headers in `axum`, you can use the
//! `AutoVaryLayer` in [`crate::auto_vary`].
//!
//! To use the `AutoVaryLayer`, you need to enable the `auto-vary` feature in your `Cargo.toml`.
//!
//! Here's an example of using the `AutoVaryLayer`:
//!
//! ```rust,ignore
//! use axum::Router;
//! use htmxtools::auto_vary::AutoVaryLayer;
//!
//! fn app() -> Router {
//! Router::new().layer(AutoVaryLayer)
//! }
//! ```