Skip to content

Commit

Permalink
feat: add form support and better routing; implement TODO app example (
Browse files Browse the repository at this point in the history
  • Loading branch information
m4tx authored Aug 19, 2024
1 parent 8e4626f commit 7867952
Show file tree
Hide file tree
Showing 19 changed files with 1,561 additions and 113 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"flareon-orm",
# Examples
"examples/hello-world",
"examples/todo-list",
]
resolver = "2"

Expand All @@ -15,13 +16,17 @@ edition = "2021"
license = "MIT OR Apache-2.0"

[workspace.dependencies]
askama = "0.12.1"
async-trait = "0.1.80"
axum = "0.7.5"
bytes = "1.6.1"
chrono = { version = "0.4.38", features = ["serde"] }
clap = { version = "4.5.8", features = ["derive", "env"] }
derive_builder = "0.20.0"
env_logger = "0.11.3"
flareon = { path = "flareon" }
flareon_macros = { path = "flareon-macros" }
form_urlencoded = "1.2.1"
indexmap = "2.2.6"
itertools = "0.13.0"
log = "0.4.22"
Expand Down
8 changes: 4 additions & 4 deletions examples/hello-world/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::sync::Arc;

use flareon::prelude::{
Body, Error, FlareonApp, FlareonProject, Request, Response, Route, StatusCode,
};
use flareon::prelude::{Body, Error, FlareonApp, FlareonProject, Response, StatusCode};
use flareon::request::Request;
use flareon::router::Route;

fn return_hello(_request: Request) -> Result<Response, Error> {
async fn return_hello(_request: Request) -> Result<Response, Error> {
Ok(Response::new_html(
StatusCode::OK,
Body::fixed("<h1>Hello Flareon!</h1>".as_bytes().to_vec()),
Expand Down
12 changes: 12 additions & 0 deletions examples/todo-list/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "example-todo-list"
version = "0.1.0"
publish = false
description = "TODO List - Flareon example."
edition = "2021"

[dependencies]
askama = "0.12.1"
flareon = { path = "../../flareon" }
tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] }
env_logger = "0.11.5"
92 changes: 92 additions & 0 deletions examples/todo-list/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use std::sync::Arc;

use askama::Template;
use flareon::forms::Form;
use flareon::prelude::{Body, Error, FlareonApp, FlareonProject, Response, Route, StatusCode};
use flareon::request::Request;
use flareon::reverse;
use tokio::sync::RwLock;

#[derive(Debug, Clone)]
struct TodoItem {
title: String,
}

#[derive(Debug, Template)]
#[template(path = "index.html")]
struct IndexTemplate<'a> {
request: &'a Request,
todo_items: Vec<TodoItem>,
}

static TODOS: RwLock<Vec<TodoItem>> = RwLock::const_new(Vec::new());

async fn index(request: Request) -> Result<Response, Error> {
let todo_items = (*TODOS.read().await).clone();
let index_template = IndexTemplate {
request: &request,
todo_items,
};
let rendered = index_template.render().unwrap();

Ok(Response::new_html(
StatusCode::OK,
Body::fixed(rendered.as_bytes().to_vec()),
))
}

#[derive(Debug, Form)]
struct TodoForm {
#[form(opt(max_length = 100))]
title: String,
}

async fn add_todo(mut request: Request) -> Result<Response, Error> {
let todo_form = TodoForm::from_request(&mut request).await.unwrap();

{
let mut todos = TODOS.write().await;
todos.push(TodoItem {
title: todo_form.title,
});
}

Ok(reverse!(request, "index"))
}

async fn remove_todo(request: Request) -> Result<Response, Error> {
let todo_id = request.path_param("todo_id").expect("todo_id not found");
let todo_id = todo_id.parse::<usize>().expect("todo_id is not a number");

{
let mut todos = TODOS.write().await;
todos.remove(todo_id);
}

Ok(reverse!(request, "index"))
}

#[tokio::main]
async fn main() {
env_logger::init();

let todo_app = FlareonApp::builder()
.urls([
Route::with_handler_and_name("/", Arc::new(Box::new(index)), "index"),
Route::with_handler_and_name("/todos/add", Arc::new(Box::new(add_todo)), "add-todo"),
Route::with_handler_and_name(
"/todos/:todo_id/remove",
Arc::new(Box::new(remove_todo)),
"remove-todo",
),
])
.build()
.unwrap();

let todo_project = FlareonProject::builder()
.register_app_with_views(todo_app, "")
.build()
.unwrap();

flareon::run(todo_project, "127.0.0.1:8000").await.unwrap();
}
28 changes: 28 additions & 0 deletions examples/todo-list/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{% let request = request %}

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TODO List</title>
</head>
<body>
<h1>TODO List</h1>
<form id="todo-form" action="{{ flareon::reverse_str!(request, "add-todo") }}" method="post">
<input type="text" id="title" name="title" placeholder="Enter a new TODO" required>
<button type="submit">Add TODO</button>
</form>
<ul id="todo-list">
{% for todo in todo_items %}
<li>
{% let todo_id = loop.index0 %}
<form action="{{ flareon::reverse_str!(request, "remove-todo", "todo_id" => todo_id) }}" method="post">
<span>{{ todo.title }}</span>
<button type="submit">Remove</button>
</form>
</li>
{% endfor %}
</ul>
</body>
</html>
15 changes: 14 additions & 1 deletion flareon-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "flareon-macros"
name = "flareon_macros"
version = "0.1.0"
edition.workspace = true
license.workspace = true
Expand All @@ -8,4 +8,17 @@ description = "Modern web framework focused on speed and ease of use - macros."
[lib]
proc-macro = true

[[test]]
name = "tests"
path = "tests/compile_tests.rs"

[dependencies]
darling = "0.20.10"
proc-macro-crate = "3.1.0"
proc-macro2 = "1.0.86"
quote = "1.0.36"
syn = { version = "2.0.74", features = ["full"] }

[dev-dependencies]
flareon.workspace = true
trybuild = { version = "1.0.99", features = ["diff"] }
Loading

0 comments on commit 7867952

Please sign in to comment.