mod client; mod error; mod model; use async_trait::async_trait; use crank_core::{ AdapterResponse, DispatchEvidence, ExecutionMode, PreparedRequest, Protocol, ProtocolAdapter, ProtocolAdapterError, RestTarget, RuntimeRequestContext, Target, }; pub use client::{ExternalReferenceFetcher, OutboundHttpPolicy, RestAdapter}; pub use error::{ExternalReferenceFetchError, RestAdapterError}; pub use model::{RestRequest, RestResponse}; #[async_trait] impl ProtocolAdapter for RestAdapter { fn protocol(&self) -> Protocol { Protocol::Rest } fn supports_mode(&self, mode: ExecutionMode) -> bool { matches!(mode, ExecutionMode::Unary) } async fn invoke_unary( &self, target: &Target, prepared: &PreparedRequest, context: &RuntimeRequestContext, ) -> Result { let target = rest_target(target)?; let request = RestRequest { path_params: prepared.path_params.clone(), query_params: prepared.query_params.clone(), headers: prepared.headers.clone(), trusted_header_names: prepared.trusted_header_names.clone(), body: prepared.body.clone(), timeout_ms: prepared.timeout_ms, }; let response = self.execute_with_context(target, &request, context).await?; Ok(AdapterResponse { status_code: response.status_code, headers: response.headers, data: response.body.clone(), body: response.body, }) } } fn rest_target(target: &Target) -> Result<&RestTarget, ProtocolAdapterError> { match target { Target::Rest(target) => Ok(target), } } impl From for ProtocolAdapterError { fn from(value: RestAdapterError) -> Self { match value { RestAdapterError::InvalidBaseUrl { .. } | RestAdapterError::InvalidConfiguration { .. } => Self::InvalidConfiguration, RestAdapterError::InvalidPathParameter { .. } | RestAdapterError::InvalidQueryParameter { .. } | RestAdapterError::InvalidHeaderName { .. } | RestAdapterError::InvalidHeaderValue { .. } => Self::InvalidPreparedRequest, RestAdapterError::RedirectNotAllowed => Self::TargetRejected, RestAdapterError::TargetNotAllowed { .. } => Self::TargetRejected, RestAdapterError::RequestTooLarge { .. } => Self::RequestTooLarge, RestAdapterError::ResponseTooLarge { .. } => Self::ResponseTooLarge { dispatch: DispatchEvidence::MayHaveDispatched, }, RestAdapterError::Transport { timeout, connect } if timeout => Self::Timeout { dispatch: if connect { DispatchEvidence::NotDispatched } else { DispatchEvidence::MayHaveDispatched }, }, RestAdapterError::Transport { connect, .. } => Self::Transport { dispatch: if connect { DispatchEvidence::NotDispatched } else { DispatchEvidence::MayHaveDispatched }, }, RestAdapterError::WindowExpired => Self::Timeout { dispatch: DispatchEvidence::MayHaveDispatched, }, RestAdapterError::UnexpectedStatus { status, .. } => Self::UnexpectedStatus { status, dispatch: DispatchEvidence::MayHaveDispatched, }, RestAdapterError::InvalidSseEvent => Self::InvalidResponse { dispatch: DispatchEvidence::MayHaveDispatched, }, } } }