momento_functions_http/invoke.rs
1use momento_functions_bytes::Data;
2use thiserror::Error;
3
4use crate::{request::Request, wit::momento::http::http};
5
6/// An error returned by an HTTP request.
7#[derive(Debug, Error)]
8pub enum HttpError {
9 /// An internal error occurred within Momento.
10 #[error("internal error")]
11 InternalError,
12 /// An error occurred while making the request.
13 #[error("request error: {0}")]
14 RequestError(String),
15 /// The provided URL was not valid.
16 #[error("invalid url '{url}': {error}")]
17 InvalidUrl { url: String, error: String },
18 /// A provided header name was not valid.
19 #[error("invalid header name '{header}': {error}")]
20 InvalidHeaderName { header: String, error: String },
21 /// A provided header value was not valid.
22 #[error("invalid header value '{value}': {error}")]
23 InvalidHeaderValue { value: String, error: String },
24}
25
26impl From<http::Error> for HttpError {
27 fn from(e: http::Error) -> Self {
28 match e {
29 http::Error::InternalError => HttpError::InternalError,
30 http::Error::RequestError(s) => HttpError::RequestError(s),
31 http::Error::InvalidUrl(u) => HttpError::InvalidUrl {
32 url: u.url,
33 error: u.error,
34 },
35 http::Error::InvalidHeaderName(h) => HttpError::InvalidHeaderName {
36 header: h.header,
37 error: h.error,
38 },
39 http::Error::InvalidHeaderValue(v) => HttpError::InvalidHeaderValue {
40 value: v.value,
41 error: v.error,
42 },
43 }
44 }
45}
46
47/// A response from an HTTP request.
48///
49/// The `body` is exposed as [`Data`] so bytes are only read when you need them.
50/// Call [`Data::into_bytes`] to fully materialize the body, or read it in
51/// chunks via the underlying buffer resource.
52pub struct Response {
53 /// The HTTP status code.
54 pub status: u16,
55 /// Response headers as name-value pairs.
56 pub headers: Vec<(String, String)>,
57 /// The response body. Read on demand to avoid unnecessary allocation.
58 pub body: Data,
59}
60
61impl From<http::Response> for Response {
62 fn from(r: http::Response) -> Self {
63 Response {
64 status: r.status,
65 headers: r.headers,
66 body: Data::from(r.body),
67 }
68 }
69}
70
71/// Send an HTTP request.
72///
73/// # Arguments
74/// * `request` - The request to send.
75///
76/// # Examples
77/// ________
78/// Send a GET request:
79/// ```rust,no_run
80/// use momento_functions_http::{invoke, Request};
81///
82/// match invoke(Request::new("https://example.com/api", "GET")) {
83/// Ok(response) => println!("status: {}", response.status),
84/// Err(e) => eprintln!("request failed: {e}"),
85/// }
86/// ```
87///
88/// Send a POST request with a JSON body:
89/// ```rust,no_run
90/// use momento_functions_http::{invoke, Request};
91///
92/// match invoke(
93/// Request::new("https://example.com/api", "POST")
94/// .with_header("Content-Type", "application/json")
95/// .with_body(b"{\"key\": \"value\"}".to_vec()),
96/// ) {
97/// Ok(response) => println!("status: {}", response.status),
98/// Err(e) => eprintln!("request failed: {e}"),
99/// }
100/// ```
101pub fn invoke(request: Request) -> Result<Response, HttpError> {
102 http::invoke(request.into())
103 .map(Into::into)
104 .map_err(Into::into)
105}