• Stars
    star
    163
  • Rank 231,141 (Top 5 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created over 1 year ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A set of htmx extractors, responders, and request guards for axum.

axum-htmx


axum-htmx is a small extension library providing extractors, responders, and request guards for htmx headers within axum.

Table of Contents

Getting Started

Run cargo add axum-htmx to add the library to your project.

Extractors

All of the htmx request headers have a supported extractor. Extractors are infallible, meaning they will always succeed and never return an error. In the case where a header is not present, the extractor will return None or false dependant on the expected return type.

Header Extractor Value
HX-Boosted HxBoosted bool
HX-Current-URL HxCurrentUrl Option<axum::http::Uri>
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>

Responders

All of the htmx response headers have a supported responder. A responder is a basic type that implements IntoResponseParts, allowing you to simply and safely apply the HX-* headers to any of your responses.

Header Responder Value
HX-Location HxLocation axum::http::Uri
HX-Push-Url HxPushUrl axum::http::Uri
HX-Redirect HxRedirect axum::http::Uri
HX-Refresh HxRefresh bool
HX-Replace-Url HxReplaceUrl axum::http::Uri
HX-Reswap HxReswap axum_htmx::responders::SwapOption
HX-Retarget HxRetarget String
HX-Reselect HxReselect String
HX-Trigger HxResponseTrigger axum_htmx::serde::HxEvent
HX-Trigger-After-Settle HxResponseTrigger axum_htmx::serde::HxEvent
HX-Trigger-After-Swap HxResponseTrigger axum_htmx::serde::HxEvent

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 redirect any requests without the header to "/" by default.

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.

Examples

Example: Extractors

In this example, we'll look for the HX-Boosted header, which is set when applying the hx-boost attribute to an element. In our case, we'll use it to determine what kind of response we send.

When is this useful? When using a templating engine, like 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.

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.

use axum::response::IntoResponse;
use axum_htmx::HxBoosted;

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
    }
}

Example: Responders

We can trigger any event being listened to by the DOM using an htmx trigger header.

use axum_htmx::HxResponseTrigger;

// When we load our page, we will trigger any event listeners for "my-event.
async fn index() -> (HxResponseTrigger, &'static str) {
    // Note: As HxResponseTrigger only implements `IntoResponseParts`, we must
    // return our trigger first here.
    (
        HxResponseTrigger::normal(["my-event", "second-event"]),
        "Hello, world!",
    )
}

htmx also allows arbitrary data to be sent along with the event, which we can use via the serde feature flag and the HxEvent type.

use serde_json::json;

// Note that we are using `HxResponseTrigger` from the `axum_htmx::serde` module
// instead of the root module.
use axum_htmx::{HxEvent, HxResponseTrigger};

async fn index() -> (HxResponseTrigger, &'static str) {
    let event = HxEvent::new_with_data(
        "my-event",
        // May be any object that implements `serde::Serialize`
        json!({"level": "info", "message": {
            "title": "Hello, world!",
            "body": "This is a test message.",
        }}),
    )
    .unwrap();

    // Note: As HxResponseTrigger only implements `IntoResponseParts`, we must
    // return our trigger first here.
    (HxResponseTrigger::normal([event]), "Hello, world!")
}

Example: Router Guard

use axum::Router;
use axum_htmx::HxRequestGuardLayer;

fn router_one() -> Router {
    Router::new()
        // Redirects to "/" if the HX-Request header is not present
        .layer(HxRequestGuardLayer::default())
}

fn router_two() -> Router {
    Router::new()
        .layer(HxRequestGuardLayer::new("/redirect-to-this-route"))
}

Feature Flags

Flag Default Description Dependencies
guards Disabled Adds request guard layers. tower, futures-core, pin-project-lite
serde Disabled Adds serde support for the HxEvent and LocationOptions serde, serde_json

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!

License

axum-htmx is dual-licensed under either

at your option.

More Repositories

1

cogwatch

Hot-reloading for discord.py-based command files.
Python
44
star
2

template-axum-htmx-tailwind

Axum-based MPA using htmx for SPA-like functionality, styled with Tailwind.
Rust
26
star
3

dpymenus

Simplified menus for discord.py developers.
Python
26
star
4

template-axum-solidjs-spa

Full-stack SPA template using SolidJS, TypeScript, and Tailwind v4. Backed by Rust with Axum and PostgreSQL.
TypeScript
21
star
5

blossom

MUD (Multi-User Dungeon) game engine written in Rust.
Rust
17
star
6

template-rocket-svelte-spa

Full-stack SPA template using Svelte, TypeScript, and Tailwind. Backed by Rust with Rocket and PostgreSQL.
Svelte
9
star
7

petrock

Leaderboard analytics for RetroMMO.
Svelte
6
star
8

iridescent

Terminal text styling via ANSI escape sequences.
Rust
4
star
9

bufferfish

Binary messaging utility library for communicating between Rust and TypeScript.
Rust
4
star
10

nectar

Telnet protocol (RFC 854) implementation via a Tokio codec.
Rust
4
star
11

jinx

CLI tool for populating new repositories with a README, licenses, and language specific files.
Rust
3
star
12

axum-tws

A high-performance WebSocket backend for axum powered by tokio-websockets.
Rust
2
star
13

libmutter-fix

Script for patching libmutter to fix /dev/uinput system freezes using x11.
Python
2
star
14

home

Personal homepage for my browsers' new tab.
HTML
1
star
15

harp

Action-based logging library and daemon.
Rust
1
star
16

osu-backup

osu! file backup script
Python
1
star
17

pyxi

A small library for interacting with .pyxel files from PyxelEdit.
Python
1
star
18

seastar

A* pathfinding algorithm implementation for uniform-cost grids.
Rust
1
star
19

axum-cc

Cache-Control middleware for axum.
Rust
1
star