Skip to main content

cli_engine/transport/
mod.rs

1//! HTTP transport helpers for command implementations.
2//!
3//! [`crate::transport::client::HttpClient`] wraps `reqwest` with the
4//! conventions CLI commands usually need: auth injection, default headers,
5//! user-agent handling, structured HTTP errors, idempotent retries, raw
6//! response helpers, multipart helpers, ETag helpers, and GraphQL envelope
7//! decoding.
8
9use std::borrow::Cow;
10
11use serde::{Deserialize, Serialize};
12
13use crate::DetailedError;
14
15/// HTTP client implementation.
16pub mod client;
17mod debug_logger;
18/// Request auth injectors.
19pub mod injector;
20
21pub use client::{
22    HttpClient, HttpClientBuilder, NoopTransportLogger, TransportLogEvent, TransportLogger,
23    debug_log_reqwest_request, debug_log_reqwest_response, default_transport_logger,
24    set_default_transport_logger, set_default_user_agent,
25};
26pub use debug_logger::StderrTransportLogger;
27pub use injector::{
28    ApiKeyInjector, AuthInjector, BasicAuthInjector, BearerTokenInjector,
29    ClientCredentialsInjector, CookieInjector, NoopInjector, ProviderBearerInjector, TokenFunc,
30};
31
32/// Structured HTTP error decoded from a backend response.
33#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, thiserror::Error)]
34#[error("{message}")]
35pub struct Error {
36    /// Error code. Backend errors are normalized to `HTTP_<status>`.
37    pub code: String,
38    /// Human-readable backend or transport error message.
39    pub message: String,
40    /// Optional backend system id.
41    #[serde(default, skip_serializing_if = "String::is_empty")]
42    pub system: String,
43    /// Optional request id returned by the backend.
44    #[serde(default, skip_serializing_if = "String::is_empty")]
45    pub request_id: String,
46}
47
48impl DetailedError for Error {
49    fn error_code(&self) -> Cow<'static, str> {
50        Cow::Owned(self.code.clone())
51    }
52
53    fn error_system(&self) -> Option<Cow<'static, str>> {
54        (!self.system.is_empty()).then(|| Cow::Owned(self.system.clone()))
55    }
56
57    fn error_request_id(&self) -> Option<Cow<'static, str>> {
58        (!self.request_id.is_empty()).then(|| Cow::Owned(self.request_id.clone()))
59    }
60}