这是indexloc提供的服务,不要输入任何密码
Skip to content

Make handler arguments optional #87

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

Merged
merged 6 commits into from
Nov 11, 2024
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
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 <valerioageno@yahoo.it>"]
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 <valerioageno@yahoo.it>"]
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