diff options
author | Michael Alyn Miller <malyn@strangeGizmo.com> | 2021-11-27 20:59:51 -0800 |
---|---|---|
committer | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2021-11-27 22:03:18 -0800 |
commit | 4940b5dd5e792811491f1c3c3b1c70c8177c7e02 (patch) | |
tree | 4d28ad21a66ecf9496c265c0844b4c4d036763bc | |
parent | 3ef2869f48556a0aae4ca861889f9fd8bea02d66 (diff) | |
download | askama-4940b5dd5e792811491f1c3c3b1c70c8177c7e02.tar.gz askama-4940b5dd5e792811491f1c3c3b1c70c8177c7e02.tar.bz2 askama-4940b5dd5e792811491f1c3c3b1c70c8177c7e02.zip |
Add Axum integration
-rw-r--r-- | .github/workflows/rust.yml | 13 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | askama/Cargo.toml | 1 | ||||
-rw-r--r-- | askama_axum/Cargo.toml | 23 | ||||
l--------- | askama_axum/LICENSE-APACHE | 1 | ||||
l--------- | askama_axum/LICENSE-MIT | 1 | ||||
-rw-r--r-- | askama_axum/README.md | 9 | ||||
-rw-r--r-- | askama_axum/src/lib.rs | 25 | ||||
-rw-r--r-- | askama_axum/templates/hello.html | 1 | ||||
-rw-r--r-- | askama_axum/tests/basic.rs | 35 | ||||
-rw-r--r-- | askama_derive/Cargo.toml | 1 | ||||
-rw-r--r-- | askama_derive/src/lib.rs | 1 | ||||
-rw-r--r-- | askama_shared/src/generator.rs | 18 | ||||
-rw-r--r-- | askama_shared/src/lib.rs | 1 | ||||
-rw-r--r-- | book/src/integrations.md | 12 |
16 files changed, 144 insertions, 1 deletions
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 398cb46..b62ae5d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -48,6 +48,19 @@ jobs: - run: cargo test --package askama_actix --all-targets - run: cargo clippy --package askama_actix --all-targets -- -D warnings + Axum: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: clippy + - run: cargo test --package askama_axum --all-targets + - run: cargo clippy --package askama_axum --all-targets -- -D warnings + Gotham: runs-on: ubuntu-latest steps: @@ -2,6 +2,7 @@ members = [ "askama", "askama_actix", + "askama_axum", "askama_gotham", "askama_derive", "askama_escape", @@ -26,7 +26,7 @@ in a for-profit context, please consider supporting my open source work on * Construct templates using a familiar, easy-to-use syntax * Benefit from the safety provided by Rust's type system * Template code is compiled into your crate for [optimal performance][benchmarks] -* Optional built-in support for Actix, Gotham, Iron, Rocket, tide, and warp web frameworks +* Optional built-in support for Actix, Axum, Gotham, Iron, Rocket, tide, and warp web frameworks * Debugging features to assist you in template development * Templates must be valid UTF-8 and produce UTF-8 when rendered * IDE support available in [JetBrains products](https://plugins.jetbrains.com/plugin/16591-askama-template-support) diff --git a/askama/Cargo.toml b/askama/Cargo.toml index 4df0021..d3aaddc 100644 --- a/askama/Cargo.toml +++ b/askama/Cargo.toml @@ -25,6 +25,7 @@ serde-json = ["askama_shared/json"] serde-yaml = ["askama_shared/yaml"] num-traits = ["askama_shared/num-traits"] with-actix-web = ["askama_derive/actix-web"] +with-axum = ["askama_derive/axum"] with-gotham = ["askama_derive/gotham"] with-iron = ["askama_derive/iron"] with-mendes = ["askama_derive/mendes"] diff --git a/askama_axum/Cargo.toml b/askama_axum/Cargo.toml new file mode 100644 index 0000000..7d3045d --- /dev/null +++ b/askama_axum/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "askama_axum" +version = "0.10.0" +authors = ["Michael Alyn Miller <malyn@strangeGizmo.com>"] +edition = "2018" +description = "Axum integration for Askama templates" +keywords = ["markup", "template", "jinja2", "html", "axum"] +categories = ["template-engine"] +homepage = "https://github.com/djc/askama" +repository = "https://github.com/djc/askama" +documentation = "https://docs.rs/askama" +license = "MIT OR Apache-2.0" +workspace = ".." +readme = "README.md" + +[dependencies] +askama = { version = "0.11.0-beta.1", path = "../askama", default-features = false, features = ["with-axum", "mime", "mime_guess"] } +axum = { version = "0.3", default-features = false } + +[dev-dependencies] +hyper = { version = "0.14", features = ["full"] } +tokio = { version = "1.0", features = ["full"] } +tower = { version = "0.4", features = ["util"] }
\ No newline at end of file diff --git a/askama_axum/LICENSE-APACHE b/askama_axum/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/askama_axum/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE
\ No newline at end of file diff --git a/askama_axum/LICENSE-MIT b/askama_axum/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/askama_axum/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT
\ No newline at end of file diff --git a/askama_axum/README.md b/askama_axum/README.md new file mode 100644 index 0000000..584dbd9 --- /dev/null +++ b/askama_axum/README.md @@ -0,0 +1,9 @@ +# askama_axum: Askama integration with Axum + +[![Documentation](https://docs.rs/askama_axum/badge.svg)](https://docs.rs/askama_axum/) +[![Latest version](https://img.shields.io/crates/v/askama_axum.svg)](https://crates.io/crates/askama_axum) +[![Build Status](https://github.com/djc/askama/workflows/CI/badge.svg)](https://github.com/djc/askama/actions?query=workflow%3ACI) +[![Chat](https://badges.gitter.im/gitterHQ/gitter.svg)](https://gitter.im/djc/askama) + +Integration of the [Askama](https://github.com/djc/askama) templating engine in +code building on the Axum web framework. diff --git a/askama_axum/src/lib.rs b/askama_axum/src/lib.rs new file mode 100644 index 0000000..0c21464 --- /dev/null +++ b/askama_axum/src/lib.rs @@ -0,0 +1,25 @@ +#![deny(elided_lifetimes_in_paths)] + +pub use askama::*; +use axum::{ + self, + body::{Bytes, Full}, + http::{Response, StatusCode}, +}; + +pub fn into_response<T: Template>(t: &T, ext: &str) -> axum::http::Response<Full<Bytes>> { + match t.render() { + Ok(body) => Response::builder() + .status(StatusCode::OK) + .header( + "content-type", + askama::mime::extension_to_mime_type(ext).to_string(), + ) + .body(body.into()) + .unwrap(), + Err(_) => Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(vec![].into()) + .unwrap(), + } +} diff --git a/askama_axum/templates/hello.html b/askama_axum/templates/hello.html new file mode 100644 index 0000000..8149be7 --- /dev/null +++ b/askama_axum/templates/hello.html @@ -0,0 +1 @@ +Hello, {{ name }}! diff --git a/askama_axum/tests/basic.rs b/askama_axum/tests/basic.rs new file mode 100644 index 0000000..acd53b7 --- /dev/null +++ b/askama_axum/tests/basic.rs @@ -0,0 +1,35 @@ +use askama::Template; +use axum::{ + body::Body, + http::{Request, StatusCode}, + routing::get, + Router, +}; +use tower::util::ServiceExt; + +#[derive(Template)] +#[template(path = "hello.html")] +struct HelloTemplate<'a> { + name: &'a str, +} + +async fn hello() -> HelloTemplate<'static> { + HelloTemplate { name: "world" } +} + +#[tokio::test] +async fn template_to_response() { + let app = Router::new().route("/", get(hello)); + + let res = app + .oneshot(Request::builder().uri("/").body(Body::empty()).unwrap()) + .await + .unwrap(); + assert_eq!(res.status(), StatusCode::OK); + + let headers = res.headers(); + assert_eq!(headers["Content-Type"], "text/html; charset=utf-8"); + + let body = hyper::body::to_bytes(res.into_body()).await.unwrap(); + assert_eq!(&body[..], b"Hello, world!"); +} diff --git a/askama_derive/Cargo.toml b/askama_derive/Cargo.toml index 92c05f3..19e327b 100644 --- a/askama_derive/Cargo.toml +++ b/askama_derive/Cargo.toml @@ -17,6 +17,7 @@ proc-macro = true config = ["askama_shared/config"] actix-web = [] +axum = [] gotham = [] iron = [] mendes = [] diff --git a/askama_derive/src/lib.rs b/askama_derive/src/lib.rs index f2bee66..35070fe 100644 --- a/askama_derive/src/lib.rs +++ b/askama_derive/src/lib.rs @@ -111,6 +111,7 @@ fn find_used_templates( const INTEGRATIONS: Integrations = Integrations { actix: cfg!(feature = "actix-web"), + axum: cfg!(feature = "axum"), gotham: cfg!(feature = "gotham"), iron: cfg!(feature = "iron"), mendes: cfg!(feature = "mendes"), diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs index 78ada4b..e121be5 100644 --- a/askama_shared/src/generator.rs +++ b/askama_shared/src/generator.rs @@ -96,6 +96,9 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { if self.integrations.actix { self.impl_actix_web_responder(&mut buf)?; } + if self.integrations.axum { + self.impl_axum_into_response(&mut buf)?; + } if self.integrations.gotham { self.impl_gotham_into_response(&mut buf)?; } @@ -222,6 +225,21 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { buf.writeln("}") } + // Implement Axum's `IntoResponse`. + fn impl_axum_into_response(&mut self, buf: &mut Buffer) -> Result<(), CompileError> { + self.write_header(buf, "::axum::response::IntoResponse", None)?; + buf.writeln( + "type Body = ::axum::body::Full<::axum::body::Bytes>;\n\ + type BodyError = std::convert::Infallible;\n\ + fn into_response(self)\ + -> ::axum::http::Response<Self::Body> {", + )?; + let ext = self.input.extension().unwrap_or("txt"); + buf.writeln(&format!("::askama_axum::into_response(&self, {:?})", ext))?; + buf.writeln("}")?; + buf.writeln("}") + } + // Implement gotham's `IntoResponse`. fn impl_gotham_into_response(&mut self, buf: &mut Buffer) -> Result<(), CompileError> { self.write_header(buf, "::askama_gotham::IntoResponse", None)?; diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs index f217cfb..8d64e7b 100644 --- a/askama_shared/src/lib.rs +++ b/askama_shared/src/lib.rs @@ -274,6 +274,7 @@ pub fn get_template_source(tpl_path: &Path) -> std::result::Result<String, Compi #[derive(Clone, Copy, Debug)] pub struct Integrations { pub actix: bool, + pub axum: bool, pub gotham: bool, pub iron: bool, pub mendes: bool, diff --git a/book/src/integrations.md b/book/src/integrations.md index a972e4d..918b887 100644 --- a/book/src/integrations.md +++ b/book/src/integrations.md @@ -20,6 +20,18 @@ a value of that type in an Actix-web handler. See [the example](https://github.com/djc/askama/blob/main/askama_actix/tests/basic.rs) from the Askama test suite for more on how to integrate. +## Axum integration + +Enabling the `with-axum` feature appends an implementation of Axum's +`IntoResponse` trait for each template type. This makes it easy to trivially +return a value of that type in a Axum handler. See +[the example](https://github.com/djc/askama/blob/main/askama_axum/tests/basic.rs) +from the Askama test suite for more on how to integrate. + +In case of a run-time error occurring during templating, the response will be of the same +signature, with a status code of `500 Internal Server Error`, mime `*/*`, and an empty `Body`. +This preserves the response chain if any custom error handling needs to occur. + ## Gotham integration Enabling the `with-gotham` feature appends an implementation of Gotham's |