server_fn/codec/
url.rs

1use super::{Encoding, FromReq, IntoReq};
2use crate::{
3    error::{FromServerFnError, IntoAppError, ServerFnErrorErr},
4    request::{ClientReq, Req},
5    ContentType,
6};
7use http::Method;
8use serde::{de::DeserializeOwned, Serialize};
9
10/// Pass arguments as a URL-encoded query string of a `GET` request.
11pub struct GetUrl;
12
13/// Pass arguments as the URL-encoded body of a `POST` request.
14pub struct PostUrl;
15
16/// Pass arguments as the URL-encoded query string of a `DELETE` request.
17/// **Note**: Browser support for `DELETE` requests without JS/WASM may be poor.
18/// Consider using a `POST` request if functionality without JS/WASM is required.
19pub struct DeleteUrl;
20
21/// Pass arguments as the URL-encoded body of a `PATCH` request.
22/// **Note**: Browser support for `PATCH` requests without JS/WASM may be poor.
23/// Consider using a `POST` request if functionality without JS/WASM is required.
24pub struct PatchUrl;
25
26/// Pass arguments as the URL-encoded body of a `PUT` request.
27/// **Note**: Browser support for `PUT` requests without JS/WASM may be poor.
28/// Consider using a `POST` request if functionality without JS/WASM is required.
29pub struct PutUrl;
30
31impl ContentType for GetUrl {
32    const CONTENT_TYPE: &'static str = "application/x-www-form-urlencoded";
33}
34
35impl Encoding for GetUrl {
36    const METHOD: Method = Method::GET;
37}
38
39impl<E, T, Request> IntoReq<GetUrl, Request, E> for T
40where
41    Request: ClientReq<E>,
42    T: Serialize + Send,
43    E: FromServerFnError,
44{
45    fn into_req(self, path: &str, accepts: &str) -> Result<Request, E> {
46        let data = serde_qs::to_string(&self).map_err(|e| {
47            ServerFnErrorErr::Serialization(e.to_string()).into_app_error()
48        })?;
49        Request::try_new_get(path, GetUrl::CONTENT_TYPE, accepts, &data)
50    }
51}
52
53impl<E, T, Request> FromReq<GetUrl, Request, E> for T
54where
55    Request: Req<E> + Send + 'static,
56    T: DeserializeOwned,
57    E: FromServerFnError,
58{
59    async fn from_req(req: Request) -> Result<Self, E> {
60        let string_data = req.as_query().unwrap_or_default();
61        let args = serde_qs::Config::new(5, false)
62            .deserialize_str::<Self>(string_data)
63            .map_err(|e| {
64                ServerFnErrorErr::Args(e.to_string()).into_app_error()
65            })?;
66        Ok(args)
67    }
68}
69
70impl ContentType for PostUrl {
71    const CONTENT_TYPE: &'static str = "application/x-www-form-urlencoded";
72}
73
74impl Encoding for PostUrl {
75    const METHOD: Method = Method::POST;
76}
77
78impl<E, T, Request> IntoReq<PostUrl, Request, E> for T
79where
80    Request: ClientReq<E>,
81    T: Serialize + Send,
82    E: FromServerFnError,
83{
84    fn into_req(self, path: &str, accepts: &str) -> Result<Request, E> {
85        let qs = serde_qs::to_string(&self).map_err(|e| {
86            ServerFnErrorErr::Serialization(e.to_string()).into_app_error()
87        })?;
88        Request::try_new_post(path, PostUrl::CONTENT_TYPE, accepts, qs)
89    }
90}
91
92impl<E, T, Request> FromReq<PostUrl, Request, E> for T
93where
94    Request: Req<E> + Send + 'static,
95    T: DeserializeOwned,
96    E: FromServerFnError,
97{
98    async fn from_req(req: Request) -> Result<Self, E> {
99        let string_data = req.try_into_string().await?;
100        let args = serde_qs::Config::new(5, false)
101            .deserialize_str::<Self>(&string_data)
102            .map_err(|e| {
103                ServerFnErrorErr::Args(e.to_string()).into_app_error()
104            })?;
105        Ok(args)
106    }
107}
108
109impl ContentType for DeleteUrl {
110    const CONTENT_TYPE: &'static str = "application/x-www-form-urlencoded";
111}
112
113impl Encoding for DeleteUrl {
114    const METHOD: Method = Method::DELETE;
115}
116
117impl<E, T, Request> IntoReq<DeleteUrl, Request, E> for T
118where
119    Request: ClientReq<E>,
120    T: Serialize + Send,
121    E: FromServerFnError,
122{
123    fn into_req(self, path: &str, accepts: &str) -> Result<Request, E> {
124        let data = serde_qs::to_string(&self).map_err(|e| {
125            ServerFnErrorErr::Serialization(e.to_string()).into_app_error()
126        })?;
127        Request::try_new_delete(path, DeleteUrl::CONTENT_TYPE, accepts, &data)
128    }
129}
130
131impl<E, T, Request> FromReq<DeleteUrl, Request, E> for T
132where
133    Request: Req<E> + Send + 'static,
134    T: DeserializeOwned,
135    E: FromServerFnError,
136{
137    async fn from_req(req: Request) -> Result<Self, E> {
138        let string_data = req.as_query().unwrap_or_default();
139        let args = serde_qs::Config::new(5, false)
140            .deserialize_str::<Self>(string_data)
141            .map_err(|e| {
142                ServerFnErrorErr::Args(e.to_string()).into_app_error()
143            })?;
144        Ok(args)
145    }
146}
147
148impl ContentType for PatchUrl {
149    const CONTENT_TYPE: &'static str = "application/x-www-form-urlencoded";
150}
151
152impl Encoding for PatchUrl {
153    const METHOD: Method = Method::PATCH;
154}
155
156impl<E, T, Request> IntoReq<PatchUrl, Request, E> for T
157where
158    Request: ClientReq<E>,
159    T: Serialize + Send,
160    E: FromServerFnError,
161{
162    fn into_req(self, path: &str, accepts: &str) -> Result<Request, E> {
163        let data = serde_qs::to_string(&self).map_err(|e| {
164            ServerFnErrorErr::Serialization(e.to_string()).into_app_error()
165        })?;
166        Request::try_new_patch(path, PatchUrl::CONTENT_TYPE, accepts, data)
167    }
168}
169
170impl<E, T, Request> FromReq<PatchUrl, Request, E> for T
171where
172    Request: Req<E> + Send + 'static,
173    T: DeserializeOwned,
174    E: FromServerFnError,
175{
176    async fn from_req(req: Request) -> Result<Self, E> {
177        let string_data = req.try_into_string().await?;
178        let args = serde_qs::Config::new(5, false)
179            .deserialize_str::<Self>(&string_data)
180            .map_err(|e| {
181                ServerFnErrorErr::Args(e.to_string()).into_app_error()
182            })?;
183        Ok(args)
184    }
185}
186
187impl ContentType for PutUrl {
188    const CONTENT_TYPE: &'static str = "application/x-www-form-urlencoded";
189}
190
191impl Encoding for PutUrl {
192    const METHOD: Method = Method::PUT;
193}
194
195impl<E, T, Request> IntoReq<PutUrl, Request, E> for T
196where
197    Request: ClientReq<E>,
198    T: Serialize + Send,
199    E: FromServerFnError,
200{
201    fn into_req(self, path: &str, accepts: &str) -> Result<Request, E> {
202        let data = serde_qs::to_string(&self).map_err(|e| {
203            ServerFnErrorErr::Serialization(e.to_string()).into_app_error()
204        })?;
205        Request::try_new_put(path, PutUrl::CONTENT_TYPE, accepts, data)
206    }
207}
208
209impl<E, T, Request> FromReq<PutUrl, Request, E> for T
210where
211    Request: Req<E> + Send + 'static,
212    T: DeserializeOwned,
213    E: FromServerFnError,
214{
215    async fn from_req(req: Request) -> Result<Self, E> {
216        let string_data = req.try_into_string().await?;
217        let args = serde_qs::Config::new(5, false)
218            .deserialize_str::<Self>(&string_data)
219            .map_err(|e| {
220                ServerFnErrorErr::Args(e.to_string()).into_app_error()
221            })?;
222        Ok(args)
223    }
224}