From 5743585a771dff03039c8e442792ca2bb70768cb Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 6 Oct 2025 01:36:36 +0300 Subject: [PATCH] implement request making --- http/src/client/mod.rs | 53 ++++++++++++++++++++++++++++-- http/src/requests/mod.rs | 6 ++-- http/src/server/context.rs | 4 +-- http/src/server/handler.rs | 17 ++++++++-- http/src/server/request/extract.rs | 2 ++ http/src/server/response/mod.rs | 6 ++-- 6 files changed, 77 insertions(+), 11 deletions(-) diff --git a/http/src/client/mod.rs b/http/src/client/mod.rs index 9c617f3..9e10f3c 100644 --- a/http/src/client/mod.rs +++ b/http/src/client/mod.rs @@ -7,7 +7,7 @@ use eva::{ use http::Method; use viendesu_core::{ - errors, + errors::{self, Aux}, requests::Response, service::{ CallStep, Session, SessionMaker, @@ -97,7 +97,56 @@ impl HttpClient { where R: Request, { - todo!() + let mut endpoint = self.options.endpoint.clone(); + if endpoint.ends_with('/') { + endpoint.push_str(path.strip_prefix('/').unwrap_or(path)); + } else { + endpoint.push_str(path); + } + + let mut req = self.client.request(method.clone(), endpoint); + if method == Method::GET { + req = req.query(&request); + } else { + let mut dst = Vec::with_capacity(128); + self.options + .format + .dump(Default::default(), &request, &mut dst); + req = req + .body(dst) + .header("content-type", self.options.format.mime_type()); + } + + if let Some(sess) = self.session { + req = req.header("authorization", format!("Bearer {}", sess.to_str())); + } + + let response = self + .client + .execute(req.build().expect("shit happens")) + .await + .map_err(|e| Aux::InternalError(format_compact!("failed to make request: {e:#}")))?; + let bytes = response + .bytes() + .await + .map_err(|e| Aux::InternalError(format_compact!("failed to read bytes: {e:#}")))?; + + #[derive(serde::Deserialize)] + #[serde(untagged)] + enum GenericResponse { + Success { ok: O }, + Error { error: errors::Generic }, + } + + let resp: GenericResponse = + self.options.format.load(&bytes).map_err(|e| { + Aux::Deserialization(format!("failed to deserialize response: {e:#}")) + })?; + + match resp { + GenericResponse::Error { error } => Err(error), + GenericResponse::Success { ok } => Ok(ok), + } } } diff --git a/http/src/requests/mod.rs b/http/src/requests/mod.rs index ec04bb5..ca774b7 100644 --- a/http/src/requests/mod.rs +++ b/http/src/requests/mod.rs @@ -1,12 +1,14 @@ pub mod status_code; -pub trait Request: Send + Sync + 'static + for<'de> serde::Deserialize<'de> { +pub trait Request: + Send + Sync + 'static + for<'de> serde::Deserialize<'de> + serde::Serialize +{ type Response: IsResponse; type Error: IsResponse; } eva::trait_set! { - pub trait IsResponse = status_code::HasStatusCode + serde::Serialize + Send + Sync + 'static; + pub trait IsResponse = status_code::HasStatusCode + for<'de> serde::Deserialize<'de> + serde::Serialize + Send + Sync + 'static; } macro_rules! impl_req { diff --git a/http/src/server/context.rs b/http/src/server/context.rs index dc0cad9..249c7da 100644 --- a/http/src/server/context.rs +++ b/http/src/server/context.rs @@ -43,8 +43,6 @@ pub async fn load_args(req: AxumRequest) -> Result, let response_format = extract::response_format(&parts).map_err(|e| response::err(Format::default(), e))?; - let request_format = - extract::request_format(&parts).map_err(|e| response::err(Format::default(), e))?; let request: R = if parts.method == Method::GET { let query = parts.uri.query().unwrap_or(""); @@ -52,6 +50,8 @@ pub async fn load_args(req: AxumRequest) -> Result, .map_err(|e| Aux::Deserialization(format!("failed to decode query: {e}"))) .map_err(|e| response::err(response_format, e))? } else { + let request_format = + extract::request_format(&parts).map_err(|e| response::err(response_format, e))?; let content_length = extract::content_length(&parts).map_err(|e| response::err(response_format, e))?; let mut data_stream = body.into_data_stream(); diff --git a/http/src/server/handler.rs b/http/src/server/handler.rs index 836859e..f3ca9d5 100644 --- a/http/src/server/handler.rs +++ b/http/src/server/handler.rs @@ -9,7 +9,10 @@ use axum::{ routing::{MethodFilter, method_routing}, }; -use viendesu_core::{errors as core_errors, service::SessionOf}; +use viendesu_core::{ + errors as core_errors, + service::{Session, SessionOf, authz::AuthenticationMut}, +}; use crate::{ format::Format, @@ -118,11 +121,21 @@ impl> FinishedHandler Ok(response::ok(resp_format, r)), Err(e) => Err(response::err(resp_format, e)), diff --git a/http/src/server/request/extract.rs b/http/src/server/request/extract.rs index 9f71448..6d02f9c 100644 --- a/http/src/server/request/extract.rs +++ b/http/src/server/request/extract.rs @@ -48,6 +48,8 @@ pub fn session_token(parts: &Parts) -> AuxResult> { ))); }; + dbg!((scheme, rest)); + match scheme { "Bearer" => rest .parse() diff --git a/http/src/server/response/mod.rs b/http/src/server/response/mod.rs index 11ebfc9..812e94e 100644 --- a/http/src/server/response/mod.rs +++ b/http/src/server/response/mod.rs @@ -2,7 +2,7 @@ use axum::{ http::StatusCode, response::{IntoResponse, Response as AxumResponse}, }; -use serde::Serialize; +use serde::{Serialize, Deserialize}; use crate::format::{DumpParams, Format}; use crate::requests::{IsResponse, status_code::HasStatusCode}; @@ -18,7 +18,7 @@ macro_rules! header { #[track_caller] pub fn err(format: Format, error: E) -> AxumResponse { - #[derive(Serialize)] + #[derive(Serialize, Deserialize)] struct Failure { pub error: E, } @@ -34,7 +34,7 @@ pub fn err(format: Format, error: E) -> AxumResponse { #[track_caller] pub fn ok(format: Format, ok: O) -> AxumResponse { - #[derive(Serialize)] + #[derive(Serialize, Deserialize)] struct Success { ok: T, }