Last active
October 26, 2024 17:16
-
-
Save davidpdrsn/7033bade01498c68dff8dd506682bdf5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::convert::Infallible; | |
use axum::{ | |
async_trait, | |
extract::FromRequestParts, | |
http::{request::Parts, Request, header::CONTENT_LENGTH}, | |
middleware::{from_fn, Next}, | |
response::{Html, IntoResponse, IntoResponseParts, Response}, | |
routing::get, | |
Router, body::{Full, self}, | |
}; | |
use maud::{html, Markup}; | |
#[tokio::main] | |
async fn main() { | |
let one = Router::new().route("/one", get(one)); | |
let two = Router::new() | |
.route("/two", get(two)) | |
.layer(from_fn(wrap_in_layout)); | |
let app = one.merge(two); | |
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()) | |
.serve(app.into_make_service()) | |
.await | |
.unwrap(); | |
} | |
// Option 1: A layout extractor | |
struct Layout { | |
current_user: String, | |
} | |
#[async_trait] | |
impl<S> FromRequestParts<S> for Layout | |
where | |
S: Send + Sync, | |
{ | |
type Rejection = std::convert::Infallible; | |
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> { | |
// extract whatever your layout needs | |
Ok(Self { | |
current_user: "Bob".to_owned(), | |
}) | |
} | |
} | |
impl Layout { | |
fn render(self, template: Markup) -> Response { | |
let with_layout = html! { | |
div { | |
h1 { | |
(format!("Welcome! {}", self.current_user)) | |
} | |
div { | |
(template) | |
} | |
} | |
}.into_string(); | |
Html(with_layout).into_response() | |
} | |
} | |
async fn one(layout: Layout) -> Response { | |
layout.render(html! { "Hello, World!" }) | |
} | |
// Option 2: Middleware | |
async fn two() -> Template { | |
Template(html! { | |
"Hello, World!" | |
}) | |
} | |
struct Template(Markup); | |
impl IntoResponseParts for Template { | |
type Error = Infallible; | |
fn into_response_parts( | |
self, | |
mut res: axum::response::ResponseParts, | |
) -> Result<axum::response::ResponseParts, Self::Error> { | |
res.extensions_mut().insert(self); | |
Ok(res) | |
} | |
} | |
impl IntoResponse for Template { | |
fn into_response(self) -> Response { | |
(self, ()).into_response() | |
} | |
} | |
async fn wrap_in_layout<B>( | |
// whatever extractors you need can go here | |
request: Request<B>, | |
next: Next<B>, | |
) -> Response { | |
// maybe this is extracted from a JWT or something | |
let current_user = "Bob".to_owned(); | |
let mut response = next.run(request).await; | |
if let Some(Template(template)) = response.extensions_mut().remove::<Template>() { | |
let with_layout = html! { | |
div { | |
h1 { | |
(format!("Welcome! {current_user}")) | |
} | |
div { | |
(template) | |
} | |
} | |
}.into_string(); | |
let new_body = Html(with_layout); | |
let (mut parts, _) = response.into_parts(); | |
parts.headers.remove(CONTENT_LENGTH); | |
(parts, new_body).into_response() | |
} else { | |
response | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment