diff --git a/crates/tuono/src/source_builder.rs b/crates/tuono/src/source_builder.rs index 7e2aefbc..90b9ef37 100644 --- a/crates/tuono/src/source_builder.rs +++ b/crates/tuono/src/source_builder.rs @@ -65,7 +65,7 @@ async fn catch_all(Path(params): Path>, request: Request // TODO: remove unwrap - let payload = tuono_lib::Payload::new(&req, Box::new("")) + let payload = tuono_lib::Payload::new(&req, &"") .client_payload() .unwrap(); diff --git a/crates/tuono_lib/Cargo.toml b/crates/tuono_lib/Cargo.toml index 9e3069a8..eb804f1d 100644 --- a/crates/tuono_lib/Cargo.toml +++ b/crates/tuono_lib/Cargo.toml @@ -25,3 +25,4 @@ erased-serde = "0.4.5" serde_json = "1.0" tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.1.2"} + diff --git a/crates/tuono_lib/src/lib.rs b/crates/tuono_lib/src/lib.rs index 21c82c0d..4b5fdb79 100644 --- a/crates/tuono_lib/src/lib.rs +++ b/crates/tuono_lib/src/lib.rs @@ -6,6 +6,6 @@ pub mod ssr; pub use payload::Payload; pub use request::Request; -pub use response::Response; +pub use response::{Props, Response}; pub use ssr_rs::Ssr; pub use tuono_lib_macros::handler; diff --git a/crates/tuono_lib/src/payload.rs b/crates/tuono_lib/src/payload.rs index cb0e34ea..f0f45dcc 100644 --- a/crates/tuono_lib/src/payload.rs +++ b/crates/tuono_lib/src/payload.rs @@ -8,11 +8,11 @@ use crate::Request; /// This is the data shared to the client pub struct Payload<'a> { router: Location<'a>, - props: Box, + props: &'a dyn Serialize, } impl<'a> Payload<'a> { - pub fn new(req: &Request<'a>, props: Box) -> Payload<'a> { + pub fn new(req: &Request<'a>, props: &'a dyn Serialize) -> Payload<'a> { Payload { router: req.location(), props, diff --git a/crates/tuono_lib/src/response.rs b/crates/tuono_lib/src/response.rs index 88d0bf18..42e504d1 100644 --- a/crates/tuono_lib/src/response.rs +++ b/crates/tuono_lib/src/response.rs @@ -1,6 +1,49 @@ +use crate::Request; +use crate::{ssr::Js, Payload}; +use axum::http::StatusCode; +use axum::response::{Html, IntoResponse}; +use axum::Json; use erased_serde::Serialize; +pub struct Props { + data: Box, + http_code: StatusCode, +} + pub enum Response { Redirect(String), - Props(Box), + Props(Props), +} + +impl Props { + pub fn new(data: impl Serialize + 'static) -> Self { + Props { + data: Box::new(data), + http_code: StatusCode::OK, + } + } +} + +impl Response { + pub fn render_to_string(&self, req: Request) -> impl IntoResponse { + match self { + Self::Props(Props { data, http_code: _ }) => { + let payload = Payload::new(&req, data).client_payload().unwrap(); + + match Js::SSR.with(|ssr| ssr.borrow_mut().render_to_string(Some(&payload))) { + Ok(html) => Html(html), + Err(_) => Html("500 Internal server error".to_string()), + } + } + // TODO: Handle here other enum arms + _ => todo!(), + } + } + + pub fn json(&self) -> impl IntoResponse { + match self { + Self::Props(Props { data, http_code: _ }) => Json(data).into_response(), + _ => axum::Json("").into_response(), + } + } } diff --git a/crates/tuono_lib_macros/src/handler.rs b/crates/tuono_lib_macros/src/handler.rs index 3ce8b70b..22beb1cd 100644 --- a/crates/tuono_lib_macros/src/handler.rs +++ b/crates/tuono_lib_macros/src/handler.rs @@ -16,51 +16,29 @@ pub fn handler_core(_args: TokenStream, item: TokenStream) -> TokenStream { #item pub async fn route( - Path(params): Path>, - State(client): State, + Path(params): Path>, + State(client): State, request: axum::extract::Request - ) -> Html { + ) -> impl IntoResponse { let pathname = &request.uri(); let headers = &request.headers(); let req = tuono_lib::Request::new(pathname, headers, params); - let local_response = #fn_name(req.clone(), client).await; - - let res = match local_response { - tuono_lib::Response::Props(val) => { - - // TODO: remove unwrap - let payload = tuono_lib::Payload::new(&req, val).client_payload().unwrap(); - - tuono_lib::ssr::Js::SSR.with(|ssr| ssr.borrow_mut().render_to_string(Some(&payload))) - }, - /// TODO: handle here redirection and rewrite - _ => Ok("500 Internal server error".to_string()) - }; - - match res { - Ok(html) => Html(html), - _ => Html("500 internal server error".to_string()) - } + #fn_name(req.clone(), client).await.render_to_string(req) } pub async fn api( - Path(params): Path>, - State(client): State, + Path(params): Path>, + State(client): State, request: axum::extract::Request - ) -> axum::response::Response { + ) -> impl IntoResponse{ let pathname = &request.uri(); let headers = &request.headers(); let req = tuono_lib::Request::new(pathname, headers, params); - let local_response = #fn_name(req.clone(), client).await; - - let res = match local_response{ - tuono_lib::Response::Props(val) => return axum::Json(val).into_response(), - _ => return axum::Json("").into_response() - }; + #fn_name(req.clone(), client).await.json() } } .into() diff --git a/examples/tutorial/src/routes/index.rs b/examples/tutorial/src/routes/index.rs index 25649768..f084cc8d 100644 --- a/examples/tutorial/src/routes/index.rs +++ b/examples/tutorial/src/routes/index.rs @@ -1,6 +1,6 @@ // src/routes/index.rs use serde::{Deserialize, Serialize}; -use tuono_lib::{Request, Response}; +use tuono_lib::{Props, Request, Response}; const ALL_POKEMON: &str = "https://pokeapi.co/api/v2/pokemon?limit=151"; @@ -20,8 +20,8 @@ async fn get_all_pokemons(_req: Request<'_>, fetch: reqwest::Client) -> Response return match fetch.get(ALL_POKEMON).send().await { Ok(res) => { let data = res.json::().await.unwrap(); - Response::Props(Box::new(data)) + Response::Props(Props::new(data)) } - Err(_err) => Response::Props(Box::new(Pokemons { results: vec![] })), + Err(_err) => Response::Props(Props::new(Pokemons { results: vec![] })), }; } diff --git a/examples/tutorial/src/routes/pokemons/[pokemon].rs b/examples/tutorial/src/routes/pokemons/[pokemon].rs index 1251e91e..64244c29 100644 --- a/examples/tutorial/src/routes/pokemons/[pokemon].rs +++ b/examples/tutorial/src/routes/pokemons/[pokemon].rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use tuono_lib::{Request, Response}; +use tuono_lib::{Props, Request, Response}; const POKEMON_API: &str = "https://pokeapi.co/api/v2/pokemon"; @@ -19,9 +19,9 @@ async fn get_pokemon(req: Request<'_>, fetch: reqwest::Client) -> Response { return match fetch.get(format!("{POKEMON_API}/{pokemon}")).send().await { Ok(res) => { let data = res.json::().await.unwrap(); - Response::Props(Box::new(data)) + Response::Props(Props::new(data)) } - Err(_err) => Response::Props(Box::new(Pokemon { + Err(_err) => Response::Props(Props::new(Pokemon { name: "Nope".to_string(), id: 0, weight: 0,