Skip to main content

fiberplane_models/providers/
http.rs

1use crate::debug_print_bytes;
2use bytes::Bytes;
3#[cfg(feature = "fp-bindgen")]
4use fp_bindgen::prelude::*;
5use serde::{Deserialize, Serialize};
6use std::collections::BTreeMap;
7use std::fmt::{self, Debug, Formatter};
8use typed_builder::TypedBuilder;
9
10/// HTTP request options.
11#[derive(Clone, Debug, Default, Deserialize, Serialize)]
12#[cfg_attr(
13    feature = "fp-bindgen",
14    derive(Serializable),
15    fp(rust_module = "fiberplane_models::providers")
16)]
17#[non_exhaustive]
18#[serde(rename_all = "camelCase")]
19pub struct HttpRequest {
20    pub url: String,
21
22    pub method: HttpRequestMethod,
23
24    #[serde(default, skip_serializing_if = "Option::is_none")]
25    pub headers: Option<BTreeMap<String, String>>,
26
27    #[serde(default, skip_serializing_if = "Option::is_none")]
28    pub body: Option<Bytes>,
29}
30
31impl HttpRequest {
32    /// Returns a new DELETE request to the given URL.
33    pub fn delete(url: impl Into<String>) -> Self {
34        Self {
35            url: url.into(),
36            method: HttpRequestMethod::Delete,
37            ..Default::default()
38        }
39    }
40
41    /// Returns a new GET request to the given URL.
42    pub fn get(url: impl Into<String>) -> Self {
43        Self {
44            url: url.into(),
45            method: HttpRequestMethod::Get,
46            ..Default::default()
47        }
48    }
49
50    /// Returns a new POST request to the given URL with the given body.
51    pub fn post(url: impl Into<String>, body: impl Into<Bytes>) -> Self {
52        Self {
53            url: url.into(),
54            method: HttpRequestMethod::Post,
55            body: Some(body.into()),
56            ..Default::default()
57        }
58    }
59
60    /// Returns a new PATCH request to the given URL with the given body.
61    pub fn patch(url: impl Into<String>, body: impl Into<Bytes>) -> Self {
62        Self {
63            url: url.into(),
64            method: HttpRequestMethod::Patch,
65            body: Some(body.into()),
66            ..Default::default()
67        }
68    }
69
70    /// Returns a new PUT request to the given URL with the given body.
71    pub fn put(url: impl Into<String>, body: impl Into<Bytes>) -> Self {
72        Self {
73            url: url.into(),
74            method: HttpRequestMethod::Put,
75            body: Some(body.into()),
76            ..Default::default()
77        }
78    }
79
80    /// Adds the given headers to the request.
81    pub fn with_headers(self, headers: impl Into<BTreeMap<String, String>>) -> Self {
82        Self {
83            headers: Some(headers.into()),
84            ..self
85        }
86    }
87}
88
89/// Possible errors that may happen during an HTTP request.
90#[derive(Clone, Deserialize, Eq, PartialEq, Serialize)]
91#[cfg_attr(
92    feature = "fp-bindgen",
93    derive(Serializable),
94    fp(rust_module = "fiberplane_models::providers")
95)]
96#[non_exhaustive]
97#[serde(tag = "type", rename_all = "snake_case")]
98pub enum HttpRequestError {
99    Offline,
100    NoRoute,
101    ConnectionRefused,
102    Timeout,
103    ResponseTooBig,
104    #[cfg_attr(feature = "fp-bindgen", fp(rename_all = "camelCase"))]
105    ServerError {
106        status_code: u16,
107        response: Bytes,
108    },
109    #[cfg_attr(feature = "fp-bindgen", fp(rename_all = "camelCase"))]
110    Other {
111        reason: String,
112    },
113}
114
115impl Debug for HttpRequestError {
116    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
117        match self {
118            Self::Offline => f.write_str("Offline"),
119            Self::NoRoute => f.write_str("NoRoute"),
120            Self::ConnectionRefused => f.write_str("ConnectionRefused"),
121            Self::Timeout => f.write_str("Timeout"),
122            Self::ResponseTooBig => f.write_str("ResponseTooBig"),
123            Self::ServerError {
124                status_code,
125                response,
126            } => f
127                .debug_struct("ServerError")
128                .field("status_code", status_code)
129                .field("response_length", &response.len())
130                .field("response", &debug_print_bytes(response))
131                .finish(),
132            Self::Other { reason } => f.debug_struct("Other").field("reason", reason).finish(),
133        }
134    }
135}
136
137/// HTTP request method.
138// Note: we use SCREAMING_SNAKE_CASE here because this is
139// effectively a constant
140#[derive(Clone, Debug, Default, Deserialize, Serialize)]
141#[cfg_attr(
142    feature = "fp-bindgen",
143    derive(Serializable),
144    fp(rust_module = "fiberplane_models::providers")
145)]
146#[non_exhaustive]
147#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
148pub enum HttpRequestMethod {
149    Delete,
150    #[default]
151    Get,
152    Head,
153    Options,
154    Patch,
155    Post,
156    Put,
157}
158
159/// Response to an HTTP request.
160#[derive(Clone, Deserialize, Serialize, TypedBuilder)]
161#[cfg_attr(
162    feature = "fp-bindgen",
163    derive(Serializable),
164    fp(rust_module = "fiberplane_models::providers")
165)]
166#[non_exhaustive]
167#[serde(rename_all = "camelCase")]
168pub struct HttpResponse {
169    #[builder(setter(into))]
170    pub body: Bytes,
171
172    #[builder(setter(into))]
173    pub headers: BTreeMap<String, String>,
174
175    pub status_code: u16,
176}
177
178impl Debug for HttpResponse {
179    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
180        f.debug_struct("HttpResponse")
181            .field("status_code", &self.status_code)
182            .field("headers", &self.headers)
183            .field("body_length", &self.body.len())
184            .field("body", &debug_print_bytes(&self.body))
185            .finish()
186    }
187}