Skip to content

Commit

Permalink
Make handler arguments optional (#87)
Browse files Browse the repository at this point in the history
* feat: support axum extractors

* chore: update tuono example

* chore: update tutorial example

* doc: update documentation

* feat: update version to v0.12.0

* fix: use clippy suggestion
  • Loading branch information
Valerioageno authored Nov 11, 2024
1 parent ae04276 commit 607da92
Show file tree
Hide file tree
Showing 12 changed files with 70 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ async fn get_all_pokemons(_req: Request, fetch: Client) -> Response {
}
```

> The first argument is always the request `req: Request` which contains the request data like the query parameters and the headers.
The rest of the arguments are optional and they don't need to be specified
if they are not used. Enabled out of the box a [Reqwest](https://docs.rs/reqwest/latest/reqwest/) HTTP client.

Now the Pokémon are correctly fetched and hydrated on the client side, so we can actually use them. Clear the `index.tsx` file and paste:

```tsx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ First, let's create a new route by just creating a new file `/pokemons/GOAT.rs`

```rs
// src/routes/pokemons/GOAT.rs
use tuono_lib::{reqwest::Client, Request, Response};
use tuono_lib::{Request, Response};

#[tuono_lib::handler]
async fn redirect_to_goat(_: Request, _: Client) -> Response {
async fn redirect_to_goat(_req: Request) -> Response {
// Of course the GOAT is mewtwo - feel free to select your favourite 😉
Response::Redirect("/pokemons/mewtwo".to_string())
}
Expand Down
2 changes: 1 addition & 1 deletion crates/tuono/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tuono"
version = "0.11.2"
version = "0.12.0"
edition = "2021"
authors = ["V. Ageno <[email protected]>"]
description = "The react/rust fullstack framework"
Expand Down
4 changes: 2 additions & 2 deletions crates/tuono_lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tuono_lib"
version = "0.11.2"
version = "0.12.0"
edition = "2021"
authors = ["V. Ageno <[email protected]>"]
description = "The react/rust fullstack framework"
Expand Down Expand Up @@ -33,7 +33,7 @@ either = "1.13.0"
tower-http = {version = "0.6.0", features = ["fs"]}
colored = "2.1.0"

tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.11.2"}
tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.12.0"}
# Match the same version used by axum
tokio-tungstenite = "0.24.0"
futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] }
Expand Down
2 changes: 1 addition & 1 deletion crates/tuono_lib_macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tuono_lib_macros"
version = "0.11.2"
version = "0.12.0"
edition = "2021"
description = "The react/rust fullstack framework"
keywords = [ "react", "typescript", "fullstack", "web", "ssr"]
Expand Down
69 changes: 53 additions & 16 deletions crates/tuono_lib_macros/src/handler.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,80 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn};
use syn::punctuated::Punctuated;
use syn::token::Comma;
use syn::{parse2, parse_macro_input, FnArg, ItemFn, Pat, Type};

fn create_struct_fn_arg(arg_name: Pat, arg_type: Type) -> FnArg {
parse2(quote! {
tuono_lib::axum::extract::State(#arg_name): tuono_lib::axum::extract::State<#arg_type>
})
.unwrap()
}

fn params_argument() -> FnArg {
parse2(quote! {
tuono_lib::axum::extract::Path(params): tuono_lib::axum::extract::Path<
std::collections::HashMap<String, String>
>
})
.unwrap()
}

fn request_argument() -> FnArg {
parse2(quote! {
request: tuono_lib::axum::extract::Request
})
.unwrap()
}
pub fn handler_core(_args: TokenStream, item: TokenStream) -> TokenStream {
let item = parse_macro_input!(item as ItemFn);

let fn_name = item.clone().sig.ident;
let fn_name = &item.sig.ident;

quote! {
use tuono_lib::axum::response::IntoResponse;
use std::collections::HashMap;
use tuono_lib::axum::extract::{State, Path};
let mut argument_names: Punctuated<Pat, Comma> = Punctuated::new();
let mut axum_arguments: Punctuated<FnArg, Comma> = Punctuated::new();

// Fn Arguments minus the first which always is the request
for (i, arg) in item.sig.inputs.iter().enumerate() {
if i == 0 {
axum_arguments.insert(i, params_argument());
continue;
}

if let FnArg::Typed(pat_type) = arg {
let index = i - 1;
let argument_name = *pat_type.pat.clone();
let argument_type = *pat_type.ty.clone();
argument_names.insert(index, argument_name.clone());
axum_arguments.insert(index, create_struct_fn_arg(argument_name, argument_type))
}
}

axum_arguments.insert(axum_arguments.len(), request_argument());

quote! {
#item

pub async fn route(
Path(params): Path<HashMap<String, String>>,
State(client): State<tuono_lib::reqwest::Client>,
request: tuono_lib::axum::extract::Request
) -> impl IntoResponse {
#axum_arguments
) -> impl tuono_lib::axum::response::IntoResponse {
let pathname = request.uri();
let headers = request.headers();

let req = tuono_lib::Request::new(pathname.to_owned(), headers.to_owned(), params);

#fn_name(req.clone(), client).await.render_to_string(req)
#fn_name(req.clone(), #argument_names).await.render_to_string(req)
}

pub async fn api(
Path(params): Path<HashMap<String, String>>,
State(client): State<tuono_lib::reqwest::Client>,
request: tuono_lib::axum::extract::Request
) -> impl IntoResponse{
#axum_arguments
) -> impl tuono_lib::axum::response::IntoResponse {
let pathname = request.uri();
let headers = request.headers();

let req = tuono_lib::Request::new(pathname.to_owned(), headers.to_owned(), params);

#fn_name(req.clone(), client).await.json()
#fn_name(req.clone(), #argument_names).await.json()
}
}
.into()
Expand Down
3 changes: 1 addition & 2 deletions examples/tuono/src/routes/index.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use serde::Serialize;
use tuono_lib::reqwest;
use tuono_lib::{Props, Request, Response};

#[derive(Serialize)]
Expand All @@ -8,7 +7,7 @@ struct MyResponse<'a> {
}

#[tuono_lib::handler]
async fn get_server_side_props(_req: Request, _fetch: reqwest::Client) -> Response {
async fn get_server_side_props(_req: Request) -> Response {
Response::Props(Props::new(MyResponse {
subtitle: "The react / rust fullstack framework",
}))
Expand Down
4 changes: 2 additions & 2 deletions examples/tutorial/src/routes/pokemons/GOAT.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// src/routes/pokemons/GOAT.rs
use tuono_lib::{reqwest::Client, Request, Response};
use tuono_lib::{Request, Response};

#[tuono_lib::handler]
async fn redirect_to_goat(_: Request, _: Client) -> Response {
async fn redirect_to_goat(_req: Request) -> Response {
Response::Redirect("/pokemons/mewtwo".to_string())
}
2 changes: 1 addition & 1 deletion packages/fs-router-vite-plugin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tuono-fs-router-vite-plugin",
"version": "0.11.2",
"version": "0.12.0",
"description": "Plugin for the tuono's file system router. Tuono is the react/rust fullstack framework",
"scripts": {
"dev": "vite build --watch",
Expand Down
2 changes: 1 addition & 1 deletion packages/lazy-fn-vite-plugin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tuono-lazy-fn-vite-plugin",
"version": "0.11.2",
"version": "0.12.0",
"description": "Plugin for the tuono's lazy fn. Tuono is the react/rust fullstack framework",
"scripts": {
"dev": "vite build --watch",
Expand Down
2 changes: 1 addition & 1 deletion packages/router/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tuono-router",
"version": "0.11.2",
"version": "0.12.0",
"description": "React routing component for the framework tuono. Tuono is the react/rust fullstack framework",
"scripts": {
"dev": "vite build --watch",
Expand Down
2 changes: 1 addition & 1 deletion packages/tuono/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tuono",
"version": "0.11.2",
"version": "0.12.0",
"description": "The react/rust fullstack framework",
"scripts": {
"dev": "vite build --watch",
Expand Down

0 comments on commit 607da92

Please sign in to comment.