Skip to content

Commit 2316dae

Browse files
committed
book: add frameworks section
1 parent 8f7c15f commit 2316dae

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed

book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
- [Configuration](./configuration.md)
88
- [Template syntax](./template_syntax.md)
99
- [Filters](./filters.md)
10+
- [Frameworks](./frameworks.md)
1011
- [Performance](./performance.md)
1112
- [Upgrading](./upgrading.md)

book/src/frameworks.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Rinja in web frame
2+
3+
Rinja's [`Template::render()`] returns <code>Result&lt;String, [rinja::Error]&gt;</code>.
4+
To make this result work in your preferred web-framework, you'll need to handle both cases:
5+
converting the `String` to a web-response with the correct `Content-Type`,
6+
and the `Error` case to a proper error message.
7+
8+
While in many cases it will be enough to simply convert the `Error` to
9+
10+
* `Box<dyn std::error::Error + Send + Sync>` using `err.into_box()` or
11+
* `std::io::Error` using `err.into_io_error()`
12+
13+
it is **recommended** to use a custom error type.
14+
This way you can display the error message in your app's layout,
15+
and you are better prepared for the likely case that your app grows in the future.
16+
Maybe you'll need to access a database and handle errors?
17+
Maybe you'll add multiple languages and you want to localize error messages?
18+
19+
The crates [`thiserror`] and [`displaydoc`] can be useful to implement this error type.
20+
21+
[`Template::render()`]: <https://docs.rs/rinja/0.3.5/rinja/trait.Template.html#method.render>
22+
[rinja::Error]: <https://docs.rs/rinja/0.3.5/rinja/enum.Error.html>
23+
[`thiserror`]: <https://crates.io/crates/thiserror>
24+
[`displaydoc`]: <https://crates.io/crates/displaydoc>
25+
26+
## Actix-Web and Rinja
27+
28+
To convert the `String` to an HTML response, you can use
29+
[`Html::new(_)`](https://docs.rs/actix-web/4.9.0/actix_web/web/struct.Html.html#method.new).
30+
31+
```rust
32+
use actix_web::Responder;
33+
use actix_web::web::Html;
34+
35+
fn handler() -> Result<impl Responder, AppError> {
36+
37+
Ok(Html::new(template.render()?))
38+
}
39+
```
40+
41+
To implement your own error type, you can use this boilerplate code:
42+
43+
```rust
44+
use actix_web::{HttpResponse, Responder};
45+
use actix_web::error::ResponseError;
46+
use actix_web::http::StatusCode;
47+
use actix_web::web::Html;
48+
use rinja::Template;
49+
50+
#[derive(Debug, displaydoc::Display, thiserror::Error)]
51+
enum AppError {
52+
/// could not render template
53+
Render(#[from] rinja::Error),
54+
}
55+
56+
impl ResponseError for AppError {
57+
fn status_code(&self) -> StatusCode {
58+
match &self {
59+
AppError::Render(_) => StatusCode::INTERNAL_SERVER_ERROR,
60+
}
61+
}
62+
}
63+
64+
impl Responder for AppError {
65+
type Body = String;
66+
67+
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
68+
#[derive(Debug, Template)]
69+
#[template(path = "error.html")]
70+
struct Tmpl<'a> { … }
71+
72+
let tmpl = Tmpl { … };
73+
if let Ok(body) = tmpl.render() {
74+
(Html::new(body), self.status_code()).respond_to(req)
75+
} else {
76+
("".to_string(), self.status_code()).respond_to(req)
77+
}
78+
}
79+
}
80+
```
81+
82+
## Axum and Rinja
83+
84+
To convert the `String` to an HTML response, you can use
85+
[`Html(_)`](https://docs.rs/axum/0.8.1/axum/response/struct.Html.html).
86+
87+
```rust
88+
use axum::response::{Html, IntoResponse};
89+
90+
async fn handler() -> Result<impl IntoResponse, AppError> {
91+
92+
Ok(Html(template.render()?))
93+
}
94+
```
95+
96+
To implement your own error type, you can use this boilerplate code:
97+
98+
```rust
99+
use axum::response::IntoResponse;
100+
use rinja::Template;
101+
102+
#[derive(Debug, displaydoc::Display, thiserror::Error)]
103+
enum AppError {
104+
/// could not render template
105+
Render(#[from] rinja::Error),
106+
}
107+
108+
impl IntoResponse for AppError {
109+
fn into_response(self) -> Response {
110+
#[derive(Debug, Template)]
111+
#[template(path = "error.html")]
112+
struct Tmpl { … }
113+
114+
let status = match &self {
115+
AppError::Render(_) => StatusCode::INTERNAL_SERVER_ERROR,
116+
};
117+
let tmpl = Tmpl { … };
118+
if let Ok(body) = tmpl.render() {
119+
(status, Html(body)).into_response()
120+
} else {
121+
(status, "Something went wrong").into_response()
122+
}
123+
}
124+
}
125+
```
126+
127+
## Warp and Rinja
128+
129+
To convert the `String` to an HTML response, you can use
130+
[`html(_)`](https://docs.rs/warp/0.3.7/warp/reply/fn.html.html).
131+
132+
```rust
133+
use warp::reply::{Reply, html};
134+
135+
fn handler() -> Result<impl Reply, AppError> {
136+
137+
Ok(html(template.render()?))
138+
}
139+
```
140+
141+
To implement your own error type, you can use this boilerplate code:
142+
143+
```rust
144+
use http::StatusCode;
145+
use warp::reply::{Reply, Response, html};
146+
147+
#[derive(Debug, displaydoc::Display, thiserror::Error)]
148+
enum AppError {
149+
/// could not render template
150+
Render(#[from] rinja::Error),
151+
}
152+
153+
impl Reply for AppError {
154+
fn into_response(self) -> Response {
155+
#[derive(Debug, Template)]
156+
#[template(path = "error.html")]
157+
struct Tmpl { … }
158+
159+
let status = match &self {
160+
AppError::Render(_) => StatusCode::INTERNAL_SERVER_ERROR,
161+
};
162+
let template = Tmpl { … };
163+
if let Ok(body) = template.render() {
164+
with_status(html(body), status).into_response()
165+
} else {
166+
status.into_response()
167+
}
168+
}
169+
}
170+
```

0 commit comments

Comments
 (0)