mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
feat: add serde-lite
codec for server functions (#2168)
This commit is contained in:
parent
f6ce82c9d1
commit
a1bd84f3dc
7 changed files with 119 additions and 20 deletions
|
@ -61,7 +61,7 @@ nightly = [
|
|||
"leptos_server/nightly",
|
||||
]
|
||||
serde = ["leptos_reactive/serde"]
|
||||
serde-lite = ["leptos_reactive/serde-lite"]
|
||||
serde-lite = ["leptos_reactive/serde-lite", "server_fn/serde-lite"]
|
||||
miniserde = ["leptos_reactive/miniserde"]
|
||||
rkyv = ["leptos_reactive/rkyv"]
|
||||
tracing = ["leptos_macro/tracing"]
|
||||
|
|
|
@ -10,7 +10,7 @@ description = "Reactive system for the Leptos web framework."
|
|||
[dependencies]
|
||||
slotmap = { version = "1", features = ["serde"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde-lite = { version = "0.4", optional = true }
|
||||
serde-lite = { version = "0.5", optional = true }
|
||||
futures = { version = "0.3" }
|
||||
js-sys = { version = "0.3", optional = true }
|
||||
miniserde = { version = "0.1", optional = true }
|
||||
|
@ -24,7 +24,7 @@ bytecheck = { version = "0.7", features = [
|
|||
"simdutf8",
|
||||
], optional = true }
|
||||
rustc-hash = "1"
|
||||
serde-wasm-bindgen = "0.5"
|
||||
serde-wasm-bindgen = "0.6"
|
||||
serde_json = "1"
|
||||
spin-sdk = { version = "2", optional = true }
|
||||
base64 = "0.21"
|
||||
|
|
|
@ -33,6 +33,7 @@ multer = { version = "3", optional = true }
|
|||
## output encodings
|
||||
# serde
|
||||
serde_json = "1"
|
||||
serde-lite = { version = "0.5", features = ["derive"], optional = true }
|
||||
futures = "0.3"
|
||||
http = { version = "1" }
|
||||
ciborium = { version = "0.2", optional = true }
|
||||
|
@ -83,6 +84,7 @@ browser = [
|
|||
"dep:wasm-bindgen-futures",
|
||||
]
|
||||
json = []
|
||||
serde-lite = ["dep:serde-lite"]
|
||||
multipart = ["dep:multer"]
|
||||
url = ["dep:serde_qs"]
|
||||
cbor = ["dep:ciborium"]
|
||||
|
|
|
@ -2,19 +2,24 @@
|
|||
mod cbor;
|
||||
#[cfg(feature = "cbor")]
|
||||
pub use cbor::*;
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
mod json;
|
||||
use http::Method;
|
||||
#[cfg(feature = "json")]
|
||||
pub use json::*;
|
||||
|
||||
#[cfg(feature = "serde-lite")]
|
||||
mod serde_lite;
|
||||
#[cfg(feature = "serde-lite")]
|
||||
pub use serde_lite::*;
|
||||
|
||||
#[cfg(feature = "rkyv")]
|
||||
mod rkyv;
|
||||
#[cfg(feature = "rkyv")]
|
||||
pub use rkyv::*;
|
||||
|
||||
#[cfg(feature = "url")]
|
||||
mod url;
|
||||
use crate::{error::ServerFnError, request::ClientReq};
|
||||
use futures::Future;
|
||||
#[cfg(feature = "url")]
|
||||
pub use url::*;
|
||||
|
||||
|
@ -24,6 +29,9 @@ mod multipart;
|
|||
pub use multipart::*;
|
||||
|
||||
mod stream;
|
||||
use crate::{error::ServerFnError, request::ClientReq};
|
||||
use futures::Future;
|
||||
use http::Method;
|
||||
pub use stream::*;
|
||||
|
||||
pub trait FromReq<CustErr, Request, Encoding>
|
||||
|
|
82
server_fn/src/codec/serde_lite.rs
Normal file
82
server_fn/src/codec/serde_lite.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use super::{Encoding, FromReq, FromRes};
|
||||
use crate::{
|
||||
error::ServerFnError,
|
||||
request::{ClientReq, Req},
|
||||
response::{ClientRes, Res},
|
||||
IntoReq, IntoRes,
|
||||
};
|
||||
use http::Method;
|
||||
use serde_lite::{Deserialize, Serialize};
|
||||
/// Pass arguments and receive responses as JSON in the body of a `POST` request.
|
||||
pub struct SerdeLite;
|
||||
|
||||
impl Encoding for SerdeLite {
|
||||
const CONTENT_TYPE: &'static str = "application/json";
|
||||
const METHOD: Method = Method::POST;
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> IntoReq<CustErr, Request, SerdeLite> for T
|
||||
where
|
||||
Request: ClientReq<CustErr>,
|
||||
T: Serialize + Send,
|
||||
{
|
||||
fn into_req(
|
||||
self,
|
||||
path: &str,
|
||||
accepts: &str,
|
||||
) -> Result<Request, ServerFnError<CustErr>> {
|
||||
let data = serde_json::to_string(
|
||||
&self
|
||||
.serialize()
|
||||
.map_err(|e| ServerFnError::Serialization(e.to_string()))?,
|
||||
)
|
||||
.map_err(|e| ServerFnError::Serialization(e.to_string()))?;
|
||||
Request::try_new_post(path, accepts, SerdeLite::CONTENT_TYPE, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Request> FromReq<CustErr, Request, SerdeLite> for T
|
||||
where
|
||||
Request: Req<CustErr> + Send + 'static,
|
||||
T: Deserialize,
|
||||
{
|
||||
async fn from_req(req: Request) -> Result<Self, ServerFnError<CustErr>> {
|
||||
let string_data = req.try_into_string().await?;
|
||||
Self::deserialize(
|
||||
&serde_json::from_str(&string_data)
|
||||
.map_err(|e| ServerFnError::Args(e.to_string()))?,
|
||||
)
|
||||
.map_err(|e| ServerFnError::Args(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Response> IntoRes<CustErr, Response, SerdeLite> for T
|
||||
where
|
||||
Response: Res<CustErr>,
|
||||
T: Serialize + Send,
|
||||
{
|
||||
async fn into_res(self) -> Result<Response, ServerFnError<CustErr>> {
|
||||
let data = serde_json::to_string(
|
||||
&self
|
||||
.serialize()
|
||||
.map_err(|e| ServerFnError::Serialization(e.to_string()))?,
|
||||
)
|
||||
.map_err(|e| ServerFnError::Serialization(e.to_string()))?;
|
||||
Response::try_from_string(SerdeLite::CONTENT_TYPE, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<CustErr, T, Response> FromRes<CustErr, Response, SerdeLite> for T
|
||||
where
|
||||
Response: ClientRes<CustErr> + Send,
|
||||
T: Deserialize + Send,
|
||||
{
|
||||
async fn from_res(res: Response) -> Result<Self, ServerFnError<CustErr>> {
|
||||
let data = res.try_into_string().await?;
|
||||
Self::deserialize(
|
||||
&&serde_json::from_str(&data)
|
||||
.map_err(|e| ServerFnError::Args(e.to_string()))?,
|
||||
)
|
||||
.map_err(|e| ServerFnError::Deserialization(e.to_string()))
|
||||
}
|
||||
}
|
|
@ -28,6 +28,9 @@ use request::Req;
|
|||
use response::{ClientRes, Res};
|
||||
#[doc(hidden)]
|
||||
pub use serde;
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "serde-lite")]
|
||||
pub use serde_lite;
|
||||
use std::{fmt::Display, future::Future, pin::Pin, str::FromStr, sync::Arc};
|
||||
#[doc(hidden)]
|
||||
pub use xxhash_rust;
|
||||
|
|
|
@ -74,10 +74,8 @@ pub fn server_macro_impl(
|
|||
} = args;
|
||||
let prefix = prefix.unwrap_or_else(|| Literal::string(default_path));
|
||||
let fn_path = fn_path.unwrap_or_else(|| Literal::string(""));
|
||||
let input = input.unwrap_or_else(|| syn::parse_quote!(PostUrl));
|
||||
let input_is_rkyv = input == "Rkyv";
|
||||
let input_is_multipart = input == "MultipartFormData";
|
||||
let input = codec_ident(server_fn_path.as_ref(), input);
|
||||
let input_ident = input.unwrap_or_else(|| syn::parse_quote!(PostUrl));
|
||||
let input = codec_ident(server_fn_path.as_ref(), input_ident.clone());
|
||||
let output = output.unwrap_or_else(|| syn::parse_quote!(Json));
|
||||
let output = codec_ident(server_fn_path.as_ref(), output);
|
||||
// default to PascalCase version of function name if no struct name given
|
||||
|
@ -309,17 +307,23 @@ pub fn server_macro_impl(
|
|||
}
|
||||
};
|
||||
|
||||
// TODO rkyv derives
|
||||
let derives = if input_is_multipart {
|
||||
quote! {}
|
||||
} else if input_is_rkyv {
|
||||
todo!("implement derives for Rkyv")
|
||||
} else {
|
||||
let (is_serde, derives) = match input_ident.to_string().as_str() {
|
||||
"Rkyv" => todo!("implement derives for Rkyv"),
|
||||
"MultipartFormData" => (false, quote! {}),
|
||||
"SerdeLite" => (
|
||||
true,
|
||||
quote! {
|
||||
Clone, #server_fn_path::serde_lite::Serialize, #server_fn_path::serde_lite::Deserialize
|
||||
},
|
||||
),
|
||||
_ => (
|
||||
true,
|
||||
quote! {
|
||||
Clone, #server_fn_path::serde::Serialize, #server_fn_path::serde::Deserialize
|
||||
}
|
||||
},
|
||||
),
|
||||
};
|
||||
let serde_path = (!input_is_multipart && !input_is_rkyv).then(|| {
|
||||
let serde_path = is_serde.then(|| {
|
||||
quote! {
|
||||
#[serde(crate = #serde_path)]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue