use crate::error::Error; use crate::response::ResponseSettings; use crate::ApiError; use crate::Request; use std::time::Duration; use fire::extractor::ExtractorError; use representation::request::SerializeError; use fire::error::ServerErrorKind; use fire::header::{HeaderValues, Method, Mime}; use fire::{Body, Response}; use tracing::info; pub fn setup_request( req: &mut fire::Request, ) -> Result<(), R::Error> { req.set_size_limit(Some(R::SIZE_LIMIT)); req.set_timeout(Some(Duration::from_secs(R::TIMEOUT as u64))); // check headers let headers_missing = R::HEADERS .iter() .any(|key| req.header().value(*key).is_none()); if headers_missing { return Err(R::Error::from_error(Error::HeadersMissing(R::HEADERS))); } Ok(()) } pub async fn deserialize_req( req: &mut fire::Request, ) -> Result { // since a get request does not have a body let's parse the query parameters if R::METHOD == Method::GET { req.deserialize_query() .map_err(|e| R::Error::from_error(Error::Deserialize(e))) } else { req.deserialize() .await .map_err(|e| R::Error::from_error(Error::Deserialize(e))) } } pub fn extraction_error(e: impl ExtractorError) -> R::Error { R::Error::from_error(Error::ExtractionError(e.into_std())) } pub fn serialize_resp( resp: &R::Response, ) -> Result { Body::serialize(resp).map_err(|e| { R::Error::from_error(Error::Serialize(SerializeError::Json(e))) }) } /// todo find a better name pub fn transform_body_to_response( res: Result<(ResponseSettings, Body), R::Error>, ) -> fire::Result { let (status, headers, body) = match res { Ok((settings, body)) => (settings.status, settings.headers, body), Err(e) => { info!(error = ?e, "api response error"); // status code should define the error and this should referenced to it let body = Body::serialize(&e).map_err(|e| { fire::Error::new(ServerErrorKind::InternalServerError, e) })?; (e.status_code(), HeaderValues::new(), body) } }; let mut resp = Response::builder() .status_code(status) .content_type(Mime::JSON) .body(body); *resp.values_mut() = headers; Ok(resp.build()) } pub fn validate_request(ty: &str) { // if it is a get request, make sure the type cannot be parsed from a a null value // since that would mean no request can go through if R::METHOD != Method::GET { return; } let r = serde_json::from_value::(serde_json::Value::Null); if r.is_ok() { panic!( "Get request cannot be parsed from a null value, \ make sure the type {ty} is not a unit struct" ); } }