axum-htmx/README.md

130 lines
4.3 KiB
Markdown
Raw Normal View History

2023-07-22 22:37:15 +02:00
# axum-htmx
2023-07-23 01:17:07 +02:00
<!-- markdownlint-disable -->
<div align="right">
<a href="https://crates.io/crates/axum-htmx">
<img src="https://img.shields.io/crates/v/axum-htmx?style=flat-square" alt="crates.io badge">
</a>
2023-07-23 02:06:25 +02:00
<a href="https://docs.rs/axum-htmx/latest/">
2023-07-23 01:17:07 +02:00
<img src="https://img.shields.io/docsrs/axum-htmx?style=flat-square" alt="docs.rs badge">
</a>
</div>
2023-07-23 01:21:58 +02:00
<br>
2023-07-23 01:17:07 +02:00
<!-- markdownlint-enable -->
2023-07-28 03:59:43 +02:00
`axum-htmx` is a small extension library providing extractors and request guards
for the various [htmx](https://htmx.org/) headers within
2023-07-23 00:50:23 +02:00
[axum](https://github.com/tokio-rs/axum). Additionally, the library exports
const values for all of the htmx headers, so there's no need to mess with
strings in your handlers.
2023-07-22 22:37:15 +02:00
2023-07-23 01:21:58 +02:00
## Getting Started
2023-07-22 22:37:15 +02:00
2023-07-23 01:21:58 +02:00
Simply run `cargo add axum-htmx` to add the library to your project.
2023-07-22 22:37:15 +02:00
2023-07-23 01:36:00 +02:00
If you are using the unreleased branch of `axum` from GitHub, you can build
against the `main` version of `axum-htmx` by adding the following to your
`Cargo.toml`:
```toml
[dependencies]
2023-07-23 01:36:30 +02:00
axum-htmx = { git = "https://github.com/robertwayne/axum-htmx" }
2023-07-23 01:36:00 +02:00
```
2023-07-23 00:50:23 +02:00
## Extractors
All of the [htmx request headers](https://htmx.org/reference/#request_headers)
have a supported extractor. Additionally, all extractors are infallible, meaning
they will always succeed and never return an error. If the header is not
present, the extractor will return `None` or `false` in most cases.
| Header | Extractor | Value |
| --- | --- | --- |
| `HX-Boosted` | `HxBoosted` | `bool` |
| `HX-Current-URL` | `HxCurrentUrl` | `Option<String>` |
| `HX-History-Restore-Request` | `HxHistoryRestoreRequest` | `bool` |
| `HX-Prompt` | `HxPrompt` | `Option<String>` |
| `HX-Request` | `HxRequest` | `bool` |
| `HX-Target` | `HxTarget` | `Option<String>` |
| `HX-Trigger-Name` | `HxTriggerName` | `Option<String>` |
| `HX-Trigger` | `HxTrigger` | `Option<String>` |
2023-07-28 03:58:53 +02:00
## Request Guards
__Requires features `guards`.__
In addition to the extractors, there is also a route-wide layer request guard
for the `HX-Request` header. This will return a `403: Forbidden` response if the
header is not present, which is useful if you want to make an entire router, say
`/api`, only accessible via htmx requests.
2023-07-28 05:04:22 +02:00
_It should be noted that this is NOT a replacement for an auth guard. A user can
trivially set the `HX-Request` header themselves. This is merely a convenience
for preventing users from receiving partial responses without context. If you
need to secure an endpoint, you should be using a proper auth system._
2023-07-28 05:03:16 +02:00
2023-07-28 03:58:53 +02:00
## Example: Extractors
2023-07-22 22:37:15 +02:00
2023-07-23 00:50:23 +02:00
In this example, we'll look for the `HX-Boosted` header, which is set when
applying the [hx-boost](https://htmx.org/attributes/hx-boost/) attribute to an
element. In our case, we'll use it to determine what kind of response we send.
2023-07-22 22:37:15 +02:00
2023-07-23 00:50:23 +02:00
When is this useful? When using a templating engine, like
[minijinja](https://github.com/mitsuhiko/minijinja), it is common to extend
different templates from a `_base.html` template. However, htmx works by sending
partial responses, so extending our `_base.html` would result in lots of extra
data being sent over the wire.
2023-07-22 22:37:15 +02:00
2023-07-23 00:50:23 +02:00
If we wanted to swap between pages, we would need to support both full template
responses and partial responses _(as the page can be accessed directly or
through a boosted anchor)_, so we look for the `HX-Boosted` header and extend
from a `_partial.html` template instead.
2023-07-22 22:37:15 +02:00
```rs
2023-07-28 03:58:53 +02:00
use axum::response::IntoResponse;
use axum_htmx::HxBoosted;
2023-07-22 22:37:15 +02:00
async fn get_index(HxBoosted(boosted): HxBoosted) -> impl IntoResponse {
if boosted {
// Send a template extending from _partial.html
} else {
// Send a template extending from _base.html
}
}
```
2023-07-28 03:58:53 +02:00
### Example: Router Guard
2023-07-23 00:50:23 +02:00
```rs
2023-07-28 03:58:53 +02:00
use axum::Router;
use axum_htmx::HxRequestGuardLayer;
fn protected_router() -> Router {
Router::new()
.layer(HxRequestGuardLayer::new())
}
2023-07-23 00:50:23 +02:00
```
2023-07-28 03:58:53 +02:00
### Feature Flags
<!-- markdownlint-disable -->
| Flag | Default | Description | Dependencies |
|-|-|-|-|
| `guards`| Disabled | Adds request guard layers. | `tower`, `futures-core`, `pin-project-lite` |
<!-- markdownlint-enable -->
2023-07-28 04:02:16 +02:00
## Contributing
Contributions are always welcome! If you have an idea for a feature or find a
bug, let me know. PR's are appreciated, but if it's not a small change, please
open an issue first so we're all on the same page!
2023-07-22 22:37:15 +02:00
## License
`axum-htmx` is dual-licensed under either
- **[MIT License](/LICENSE-MIT)**
- **[Apache License, Version 2.0](/LICENSE-APACHE)**
2023-07-22 22:37:15 +02:00
at your option.