agentkit-http 0.9.1

HTTP client abstraction used across agentkit. Default reqwest-backed implementation behind an opt-out feature; BYO impls plug in via the HttpClient trait.
Documentation
use bytes::{Bytes, BytesMut};
use futures_util::{StreamExt, stream::BoxStream};
use http::{HeaderMap, StatusCode};
use serde::de::DeserializeOwned;

use crate::HttpError;

pub type BodyStream = BoxStream<'static, Result<Bytes, HttpError>>;

pub struct HttpResponse {
    status: StatusCode,
    headers: HeaderMap,
    final_url: String,
    body: BodyStream,
}

impl HttpResponse {
    pub fn new(
        status: StatusCode,
        headers: HeaderMap,
        final_url: String,
        body: BodyStream,
    ) -> Self {
        Self {
            status,
            headers,
            final_url,
            body,
        }
    }

    pub fn status(&self) -> StatusCode {
        self.status
    }

    pub fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    pub fn url(&self) -> &str {
        &self.final_url
    }

    pub fn bytes_stream(self) -> BodyStream {
        self.body
    }

    pub async fn bytes(self) -> Result<Bytes, HttpError> {
        let mut stream = self.body;
        let mut buf = BytesMut::new();
        while let Some(chunk) = stream.next().await {
            buf.extend_from_slice(&chunk?);
        }
        Ok(buf.freeze())
    }

    pub async fn text(self) -> Result<String, HttpError> {
        let bytes = self.bytes().await?;
        String::from_utf8(bytes.to_vec()).map_err(|e| HttpError::Body(Box::new(e)))
    }

    pub async fn json<T: DeserializeOwned>(self) -> Result<T, HttpError> {
        let bytes = self.bytes().await?;
        serde_json::from_slice(&bytes).map_err(HttpError::Deserialize)
    }

    pub fn error_for_status(self) -> Result<Self, HttpError> {
        if self.status.is_client_error() || self.status.is_server_error() {
            Err(HttpError::Other(format!(
                "response returned status {}",
                self.status
            )))
        } else {
            Ok(self)
        }
    }
}