mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-25 12:52:47 -07:00
Make handler arguments optional (#87)
* 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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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;
|
||||
|
||||
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! {
|
||||
use tuono_lib::axum::response::IntoResponse;
|
||||
use std::collections::HashMap;
|
||||
use tuono_lib::axum::extract::{State, Path};
|
||||
|
||||
#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()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use serde::Serialize;
|
||||
use tuono_lib::reqwest;
|
||||
use tuono_lib::{Props, Request, Response};
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -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",
|
||||
}))
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user