html_form_actions 0.2.0

Generate HTML Form parsers and routing logic for Form Actions
Documentation
use crate::{BuildExt, actions};

#[test]
fn basic() {
    #[actions(axum)]
    mod page {
        use axum::routing::get;

        use crate as html_form_actions;

        const PATH: &str = "/basic";

        async fn page_handler() -> maud::PreEscaped<String> {
            maud::html! {
                @let basic_action::Form { action, a_name } = basic_action::FORM;
                form action=(action) {
                    label { "A" input name=(a_name); }
                }
            }
        }

        #[action]
        async fn basic_action(#[form_input] a: i32) -> String {
            std::format!("a = {a}")
        }

        pub fn route(router: axum::Router) -> axum::Router {
            router.route(PATH, get(page_handler).post(actions_handler))
        }
    }

    axum::Router::new().with(page::route).into_make_service();
}

#[test]
fn state() {
    #[actions(axum, state = AppState)]
    mod page {
        use axum::{extract::State, routing::get};

        use crate as html_form_actions;

        #[derive(Clone)]
        pub struct AppState {
            pub value: i32,
        }

        const PATH: &str = "/state";

        async fn page_handler() -> maud::PreEscaped<String> {
            maud::html! {
                @let state_action::Form { action, a_name } = state_action::FORM;
                form action=(action) {
                    label { "A" input name=(a_name); }
                }
            }
        }

        #[action]
        async fn state_action(
            #[form_input] a: i32,
            State(AppState { value }): State<AppState>,
        ) -> String {
            std::format!("a = {a}, value = {value}")
        }

        pub fn route(router: axum::Router<AppState>) -> axum::Router<AppState> {
            router.route(PATH, get(page_handler).post(actions_handler))
        }
    }

    axum::Router::new()
        .with(page::route)
        .with_state(page::AppState { value: 42 })
        .into_make_service();
}

#[test]
fn named_form() {
    #[actions(axum(form = named_form::NamedForm))]
    mod page {
        use axum::routing::get;

        use crate as html_form_actions;

        mod named_form {
            pub use axum::extract::Form as NamedForm;
        }

        const PATH: &str = "/named_form";

        async fn page_handler() -> maud::PreEscaped<String> {
            maud::html! {
                @let named_form_action::Form { action, a_name } = named_form_action::FORM;
                form action=(action) {
                    label { "A" input name=(a_name); }
                }
            }
        }

        #[action]
        async fn named_form_action(#[form_input] a: i32) -> String {
            std::format!("a = {a}")
        }

        pub fn route(router: axum::Router) -> axum::Router {
            router.route(PATH, get(page_handler).post(actions_handler))
        }
    }

    axum::Router::new().with(page::route).into_make_service();
}

#[test]
fn named_handler() {
    #[actions(axum(handler = named_actions_handler))]
    mod page {
        use axum::routing::get;

        use crate as html_form_actions;

        const PATH: &str = "/named_handler";

        async fn page_handler() -> maud::PreEscaped<String> {
            maud::html! {
                @let named_handler::Form { action, a_name } = named_handler::FORM;
                form action=(action) {
                    label { "A" input name=(a_name); }
                }
            }
        }

        #[action]
        async fn named_handler(#[form_input] a: i32) -> String {
            std::format!("a = {a}")
        }

        pub fn route(router: axum::Router) -> axum::Router {
            router.route(PATH, get(page_handler).post(named_actions_handler))
        }
    }

    axum::Router::new().with(page::route).into_make_service();
}

#[test]
fn custom_action() {
    #[actions(axum)]
    mod page {
        use axum::routing::get;

        use crate as html_form_actions;

        const PATH: &str = "/custom_action";

        async fn page_handler() -> maud::PreEscaped<String> {
            maud::html! {
                @let basic_action::Form { action, a_name } = basic_action::FORM;
                form action=(action) {
                    label { "A" input name=(a_name); }
                }
            }
        }

        #[action]
        async fn basic_action(#[form_input] a: i32) -> String {
            std::format!("a = {a}")
        }

        #[derive(serde::Deserialize)]
        struct CustomActionForm {
            a: i32,
        }

        #[derive(serde::Deserialize, html_form_actions_macros::FormInputNames)]
        struct NamedCustomActionForm {
            a: i32,
        }

        #[action(custom)]
        async fn custom_action(
            axum::extract::Form(CustomActionForm { a }): axum::Form<CustomActionForm>,
        ) -> String {
            std::format!("a = {a}")
        }

        #[action(custom = super::named_custom_action_form)]
        async fn custom_action_with_named_form(
            axum::extract::Form(NamedCustomActionForm { a }): axum::Form<NamedCustomActionForm>,
        ) -> String {
            std::format!("a = {a}")
        }

        pub fn route(router: axum::Router) -> axum::Router {
            router.route(PATH, get(page_handler).post(actions_handler))
        }
    }

    axum::Router::new().with(page::route).into_make_service();
}