aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Michael Alyn Miller <malyn@strangeGizmo.com>2021-11-27 20:59:51 -0800
committerLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2021-11-27 22:03:18 -0800
commit4940b5dd5e792811491f1c3c3b1c70c8177c7e02 (patch)
tree4d28ad21a66ecf9496c265c0844b4c4d036763bc
parent3ef2869f48556a0aae4ca861889f9fd8bea02d66 (diff)
downloadaskama-4940b5dd5e792811491f1c3c3b1c70c8177c7e02.tar.gz
askama-4940b5dd5e792811491f1c3c3b1c70c8177c7e02.tar.bz2
askama-4940b5dd5e792811491f1c3c3b1c70c8177c7e02.zip
Add Axum integration
-rw-r--r--.github/workflows/rust.yml13
-rw-r--r--Cargo.toml1
-rw-r--r--README.md2
-rw-r--r--askama/Cargo.toml1
-rw-r--r--askama_axum/Cargo.toml23
l---------askama_axum/LICENSE-APACHE1
l---------askama_axum/LICENSE-MIT1
-rw-r--r--askama_axum/README.md9
-rw-r--r--askama_axum/src/lib.rs25
-rw-r--r--askama_axum/templates/hello.html1
-rw-r--r--askama_axum/tests/basic.rs35
-rw-r--r--askama_derive/Cargo.toml1
-rw-r--r--askama_derive/src/lib.rs1
-rw-r--r--askama_shared/src/generator.rs18
-rw-r--r--askama_shared/src/lib.rs1
-rw-r--r--book/src/integrations.md12
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:
diff --git a/Cargo.toml b/Cargo.toml
index 2971a14..fd273c7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,6 +2,7 @@
members = [
"askama",
"askama_actix",
+ "askama_axum",
"askama_gotham",
"askama_derive",
"askama_escape",
diff --git a/README.md b/README.md
index a1b0156..5e077c1 100644
--- a/README.md
+++ b/README.md
@@ -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