maud/docs/content/web-frameworks.md
David Pedersen 6e3222f57a
Update to axum-core 0.1 ()
* Update to axum-core 0.1

Together with the new 0.4 release of `axum` we made a new crate called
[`axum-core`]. `axum-core` has a small API and is less likely to receive
breaking changes. Therefore its recommended for libraries to depend on
`axum-core` instead of `axum`.

So this updates `maud` to use `axum-core`.

Note this is a breaking change since `axum-core` requires `axum` 0.4.

[`axum-core`]: https://crates.io/crates/axum-core

* Update changelog link

* fix test
2021-12-08 19:12:00 +11:00

3.6 KiB

Web framework integration

Maud includes support for these web frameworks: Actix, Rocket, Rouille, and Tide.

Actix

Actix support is available with the "actix-web" feature:

# ...
[dependencies]
maud = { version = "*", features = ["actix-web"] }
# ...

Actix request handlers can use a Markup that implements the actix_web::Responder trait.

use actix_web::{get, App, HttpServer, Result as AwResult};
use maud::{html, Markup};
use std::io;

#[get("/")]
async fn index() -> AwResult<Markup> {
    Ok(html! {
        html {
            body {
                h1 { "Hello World!" }
            }
        }
    })
}

#[actix_web::main]
async fn main() -> io::Result<()> {
    HttpServer::new(|| App::new().service(index))
        .bind(("127.0.0.1", 8080))?
        .run()
        .await
}

Rocket

Rocket works in a similar way, except using the rocket feature:

# ...
[dependencies]
maud = { version = "*", features = ["rocket"] }
# ...

This adds a Responder implementation for the Markup type, so you can return the result directly:

#![feature(decl_macro)]

use maud::{html, Markup};
use rocket::{get, routes};
use std::borrow::Cow;

#[get("/<name>")]
fn hello<'a>(name: Cow<'a, str>) -> Markup {
    html! {
        h1 { "Hello, " (name) "!" }
        p { "Nice to meet you!" }
    }
}

fn main() {
    rocket::ignite().mount("/", routes![hello]).launch();
}

Rouille

Unlike with the other frameworks, Rouille doesn't need any extra features at all! Calling Response::html on the rendered Markup will Just Work®.

use maud::html;
use rouille::{Response, router};

fn main() {
    rouille::start_server("localhost:8000", move |request| {
        router!(request,
            (GET) (/{name: String}) => {
                Response::html(html! {
                    h1 { "Hello, " (name) "!" }
                    p { "Nice to meet you!" }
                })
            },
            _ => Response::empty_404()
        )
    });
}

Tide

Tide support is available with the "tide" feature:

# ...
[dependencies]
maud = { version = "*", features = ["tide"] }
# ...

This adds an implementation of From<PreEscaped<String>> for the Response struct. Once provided, callers may return results of html! directly as responses:

use maud::html;
use tide::Request;
use tide::prelude::*;

#[async_std::main]
async fn main() -> tide::Result<()> {
    let mut app = tide::new();
    app.at("/hello/:name").get(|req: Request<()>| async move {
        let name: String = req.param("name")?.parse()?;
        Ok(html! {
            h1 { "Hello, " (name) "!" }
            p { "Nice to meet you!" }
        })
    });
    app.listen("127.0.0.1:8080").await?;
    Ok(())
}

Axum

Axum support is available with the "axum" feature:

# ...
[dependencies]
maud = { version = "*", features = ["axum"] }
# ...

This adds an implementation of IntoResponse for Markup/PreEscaped<String>. This then allows you to use it directly as a response!

use maud::{html, Markup};
use axum::{Router, routing::get};

async fn hello_world() -> Markup {
    html! {
        h1 { "Hello, World!" }
    }
}

#[tokio::main]
async fn main() {
    // build our application with a single route
    let app = Router::new().route("/", get(hello_world));

    // run it with hyper on localhost:3000
    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}