Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

htmlx example #97

Merged
merged 6 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[workspace]
resolver = "2"
members = [
"viz",
"viz-core",
Expand Down Expand Up @@ -30,8 +31,8 @@ members = [
"examples/tracing",
"examples/graceful-shutdown",
"examples/databases/*",
"examples/htmlx",
]
resolver = "2"

[workspace.package]
version = "0.5.1"
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Here you can find a lot of small crabs 🦀.
* [maud](templates/maud)
* [minijinja](templates/minijinja)
* [Tracing aka logging](tracing)
* [htmlx](htmlx)

## Usage

Expand Down
2 changes: 1 addition & 1 deletion examples/databases/sea-orm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ publish = false
viz = { workspace = true, features = ["serve"] }
serde.workspace = true

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
sea-orm = { version = "0.12", features = ["runtime-tokio-rustls", "sqlx-sqlite"] }

[lints]
Expand Down
5 changes: 1 addition & 4 deletions examples/forms/form/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,4 @@ publish = false
viz.workspace = true

serde = { workspace = true, features = ["derive"] }
tokio = { workspace = true, features = [
"rt-multi-thread",
"macros",
] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
2 changes: 1 addition & 1 deletion examples/graceful-shutdown/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ publish = false
[dependencies]
viz.workspace = true

tokio = { workspace = true, features = [ "rt-multi-thread", "macros", "time" ] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "time"] }
2 changes: 1 addition & 1 deletion examples/hello-world/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ publish = false
[dependencies]
viz.workspace = true

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
15 changes: 15 additions & 0 deletions examples/htmlx/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "htmlx"
version = "0.1.0"
edition.workspace = true
publish = false

[dependencies]
viz = { workspace = true, features = ["serve"] }

serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }

handlebars = { version = "4.5", features = ["dir_source"] }
once_cell = "1.19"
111 changes: 111 additions & 0 deletions examples/htmlx/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// #![deny(warnings)]

use handlebars::Handlebars;
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::{
net::SocketAddr,
sync::{Arc, Mutex, PoisonError},
};
use tokio::net::TcpListener;
use viz::{
header::HeaderValue, middleware::limits, serve, types::State, Error, IntoResponse, Request,
RequestExt, Response, ResponseExt, Result, Router, StatusCode, Tree,
};

/// In-memory todo store
type DB = Arc<Mutex<Vec<Todo>>>;

#[derive(Debug, Clone, Deserialize, Serialize)]
struct Todo {
pub text: String,
pub completed: bool,
}

static TPLS: Lazy<Handlebars> = Lazy::new(|| {
let mut h = Handlebars::new();
h.register_templates_directory(".html", "examples/htmlx/templates")
.unwrap();
h
});

#[allow(clippy::needless_pass_by_value)]
fn into_error<T>(e: PoisonError<T>) -> Error {
e.to_string().into_error()
}

async fn index(req: Request) -> Result<Response> {
let todos = req
.state::<DB>()
.unwrap()
.lock()
.map_err(into_error)?
.clone();
let body = TPLS
.render(
"index",
&json!({
"todos": todos
}),
)
.map_err(Error::normal)?;
Ok(Response::html(body))
}

async fn list(req: Request) -> Result<Response> {
let todos = req
.state::<DB>()
.unwrap()
.lock()
.map_err(into_error)?
.clone();
let body = TPLS
.render(
"todos",
&json!({
"todos": todos
}),
)
.map_err(Error::normal)?;
Ok(Response::html(body))
}

async fn create(mut req: Request) -> Result<Response> {
let todo = req.form::<Todo>().await?;
let db = req.state::<DB>().unwrap();

let mut todos = db.lock().map_err(into_error)?;
todos.push(todo);

let mut resp = StatusCode::CREATED.into_response();
resp.headers_mut()
.insert("HX-Trigger", HeaderValue::from_static("newTodo"));
Ok(resp)
}

#[tokio::main]
async fn main() -> Result<()> {
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
let listener = TcpListener::bind(addr).await?;
println!("listening on http://{addr}");

let app = Router::new()
.get("/", index)
.get("/todos", list)
.post("/todos", create)
.any("/*", |_| async { Ok(Response::text("Welcome!")) })
.with(State::new(DB::default()))
.with(limits::Config::default());
let tree = Arc::new(Tree::from(app));

loop {
let (stream, addr) = listener.accept().await?;
let tree = tree.clone();
tokio::task::spawn(async move {
if let Err(err) = serve(stream, tree, Some(addr)).await {
eprintln!("Error while serving HTTP connection: {err}");
}
});
}
}
30 changes: 30 additions & 0 deletions examples/htmlx/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<title>Viz & htmlx</title>
<script src="https://unpkg.com/[email protected]" integrity="sha384-QFjmbokDn2DjBjq+fM+8LUIVrAgqcNW2s0PjAxHETgRn9l4fvX31ZxDxvwQnyMOX" crossorigin="anonymous"></script>
</head>
<body>
<form
hx-post="/todos"
hx-on="htmx:configRequest: event.detail.parameters.completed = completed.checked"
hx-swap="none"
id="form">
<input type="checkbox" name="completed" id="completed" />
<label for="completed">Done</label>
<input type="text" name="text" id="text" />
<button type="submit">Add</button>
</form>
<div
hx-get="/todos"
hx-trigger="newTodo from:form"
id="todos"
>
<ul id="list">
{{#each todos as | todo |}}
<li>{{text}}</li>
{{/each}}
</ul>
</div>
</body>
</html>
5 changes: 5 additions & 0 deletions examples/htmlx/templates/todos.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<ul>
{{#each todos as | todo |}}
<li>{{text}} {{complated}}</li>
{{/each}}
</ul>
7 changes: 2 additions & 5 deletions examples/limits/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,5 @@ publish = false
[dependencies]
viz = { workspace = true, features = ["limits", "json", "form", "multipart"] }

serde = {version = "1.0", features = ["derive"] }
tokio = { workspace = true, features = [
"rt-multi-thread",
"macros",
] }
serde = { version = "1.0", features = ["derive"] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
2 changes: 1 addition & 1 deletion examples/otel/metrics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ publish = false
[dependencies]
viz = { workspace = true, features = ["otel-metrics", "otel-prometheus"] }

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
opentelemetry = { workspace = true, features = ["metrics"]}
opentelemetry_sdk = { workspace = true, features = ["metrics"] }
2 changes: 1 addition & 1 deletion examples/otel/tracing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ publish = false
[dependencies]
viz = { workspace = true, features = ["otel-tracing"] }

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
opentelemetry.workspace = true
opentelemetry_sdk = { workspace = true, features = ["trace", "rt-tokio-current-thread"] }
opentelemetry-jaeger = { version = "0.20", features = ["rt-tokio-current-thread"]}
1 change: 1 addition & 0 deletions examples/templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
## Examples

* [askama](askama)
* [handlebars](../htmlx)
* [markup](markup)
* [maud](maud)
* [minijinja](minijinja)
Expand Down
2 changes: 1 addition & 1 deletion examples/templates/askama/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ publish = false
[dependencies]
viz.workspace = true

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
askama = "0.12"
2 changes: 1 addition & 1 deletion examples/templates/markup/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ publish = false
[dependencies]
viz.workspace = true

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }

markup = "0.15"
v_htmlescape = "0.15"
2 changes: 1 addition & 1 deletion examples/templates/maud/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ publish = false
[dependencies]
viz.workspace = true

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
maud = "0.25"
2 changes: 1 addition & 1 deletion examples/templates/minijinja/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ publish = false
viz.workspace = true

serde.workspace = true
tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
minijinja = { version = "1", features = ["loader"] }
once_cell = "1.19"
5 changes: 2 additions & 3 deletions examples/templates/minijinja/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use serde::Serialize;
use tokio::net::TcpListener;
use viz::{serve, BytesMut, Error, Request, Response, ResponseExt, Result, Router, Tree};

static MINIJINJA: Lazy<Environment> = Lazy::new(|| {
static TPLS: Lazy<Environment> = Lazy::new(|| {
let mut env = Environment::new();
env.set_loader(path_loader("examples/templates/minijinja/templates"));
env
Expand All @@ -24,8 +24,7 @@ struct User<'a> {
async fn index(_: Request) -> Result<Response> {
let mut buf = BytesMut::with_capacity(512);
buf.extend(
MINIJINJA
.get_template("index.html")
TPLS.get_template("index.html")
.map_err(Error::normal)?
.render(context! {
title => "Viz.rs",
Expand Down
2 changes: 1 addition & 1 deletion examples/templates/tera/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ publish = false
viz.workspace = true

serde.workspace = true
tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
tera = "1.18"
once_cell = "1.19"
4 changes: 2 additions & 2 deletions examples/templates/tera/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use tera::{Context, Tera};
use tokio::net::TcpListener;
use viz::{serve, BytesMut, Error, Request, Response, ResponseExt, Result, Router, Tree};

static TERA: Lazy<Tera> =
static TPLS: Lazy<Tera> =
Lazy::new(|| Tera::new("examples/templates/tera/templates/**/*").unwrap());

#[derive(Serialize)]
Expand All @@ -36,7 +36,7 @@ async fn index(_: Request) -> Result<Response> {
);
let mut buf = BytesMut::with_capacity(512);
buf.extend(
TERA.render("index.html", &ctx)
TPLS.render("index.html", &ctx)
.map_err(Error::normal)?
.as_bytes(),
);
Expand Down
Loading