99 lines
3.6 KiB
Rust
99 lines
3.6 KiB
Rust
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<AdapterResponse, ProtocolAdapterError> {
|
|
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<RestAdapterError> 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,
|
|
},
|
|
}
|
|
}
|
|
}
|