dioxus_fullstack/payloads/
axum_types.rs1use super::*;
2use crate::{ClientResponse, FromResponse};
3pub use axum::extract::Json;
4use axum::response::{Html, NoContent, Redirect};
5use dioxus_fullstack_core::{RequestError, ServerFnError};
6use futures::StreamExt;
7use http::StatusCode;
8use std::future::Future;
9
10impl<T: From<String>> FromResponse for Html<T> {
11 fn from_response(res: ClientResponse) -> impl Future<Output = Result<Self, ServerFnError>> {
12 async move {
13 let content = res.text().await?;
14 Ok(Html(content.into()))
15 }
16 }
17}
18
19impl<T> IntoRequest for Json<T>
20where
21 T: Serialize + 'static + DeserializeOwned,
22{
23 fn into_request(self, request: ClientRequest) -> impl Future<Output = ClientResult> + 'static {
24 async move { request.send_json(&self.0).await }
25 }
26}
27
28impl<T: DeserializeOwned> FromResponse for Json<T> {
29 fn from_response(res: ClientResponse) -> impl Future<Output = Result<Self, ServerFnError>> {
30 async move {
31 let data = res.json::<T>().await?;
32 Ok(Json(data))
33 }
34 }
35}
36
37impl FromResponse for Redirect {
38 fn from_response(res: ClientResponse) -> impl Future<Output = Result<Self, ServerFnError>> {
39 async move {
40 let location = res
41 .headers()
42 .get(http::header::LOCATION)
43 .ok_or_else(|| RequestError::Redirect("Missing Location header".into()))?
44 .to_str()
45 .map_err(|_| RequestError::Redirect("Invalid Location header".into()))?;
46 match res.status() {
47 StatusCode::SEE_OTHER => Ok(Redirect::to(location)),
48 StatusCode::TEMPORARY_REDIRECT => Ok(Redirect::temporary(location)),
49 StatusCode::PERMANENT_REDIRECT => Ok(Redirect::permanent(location)),
50 _ => Err(RequestError::Redirect("Not a redirect status code".into()).into()),
51 }
52 }
53 }
54}
55
56impl FromResponse for NoContent {
57 fn from_response(res: ClientResponse) -> impl Future<Output = Result<Self, ServerFnError>> {
58 async move {
59 let status = res.status();
60 if status == StatusCode::NO_CONTENT {
61 Ok(NoContent)
62 } else {
63 let body = res.text().await.unwrap_or_else(|_| "".into());
64 Err(RequestError::Status(body, status.into()).into())
65 }
66 }
67 }
68}
69
70impl FromResponse for axum::response::Response {
76 fn from_response(res: ClientResponse) -> impl Future<Output = Result<Self, ServerFnError>> {
77 async move {
78 let parts = res.make_parts();
79 let body = axum::body::Body::from_stream(res.bytes_stream());
80 let response = axum::response::Response::from_parts(parts, body);
81 Ok(response)
82 }
83 }
84}
85
86impl IntoRequest for axum::extract::Request {
92 fn into_request(
93 self,
94 mut request: ClientRequest,
95 ) -> impl Future<Output = Result<ClientResponse, RequestError>> + 'static {
96 async move {
97 let (parts, body) = self.into_parts();
98
99 for (key, value) in &parts.headers {
100 request = request.header(key, value)?;
101 }
102
103 request
104 .send_body_stream(
105 body.into_data_stream()
106 .map(|res| res.map_err(|_| StreamingError::Failed)),
107 )
108 .await
109 }
110 }
111}