Skip to main content

crux_http/
lib.rs

1#![allow(clippy::unsafe_derive_deserialize)]
2//! A HTTP client for use with Crux
3//!
4//! `crux_http` allows Crux apps to make HTTP requests by asking the Shell to perform them.
5//!
6//! This is still work in progress and large parts of HTTP are not yet supported.
7// #![warn(missing_docs)]
8
9mod config;
10mod error;
11mod expect;
12mod request;
13mod request_builder;
14mod response;
15
16mod body;
17pub mod client;
18pub mod command;
19#[cfg(feature = "http-types")]
20mod compat;
21pub mod middleware;
22pub mod protocol;
23pub mod testing;
24
25use std::marker::PhantomData;
26
27pub use crate::body::Body;
28pub use http;
29pub use http::Method;
30pub use mime;
31pub use url::Url;
32
33#[cfg(feature = "http-types")]
34pub use http_types;
35
36pub use crate::protocol::{HttpRequest, HttpResponse};
37
38pub use self::{config::Config, error::HttpError, request::Request};
39pub use response::Response;
40
41pub use request_builder::RequestBuilder;
42pub use response::RawResponse;
43
44use client::Client;
45
46pub type Result<T> = std::result::Result<T, HttpError>;
47
48pub struct Http<Effect, Event> {
49    effect: PhantomData<Effect>,
50    event: PhantomData<Event>,
51}
52
53impl<Effect, Event> Http<Effect, Event>
54where
55    Effect: Send + From<crux_core::Request<HttpRequest>> + 'static,
56    Event: Send + 'static,
57{
58    /// Instruct the Shell to perform a HTTP GET request to the provided `url`.
59    ///
60    /// The request can be configured via associated functions on the returned
61    /// [`RequestBuilder`] and then converted to a [`Command`](crux_core::Command)
62    /// with [`RequestBuilder::build`].
63    ///
64    /// # Panics
65    ///
66    /// This will panic if a malformed URL is passed.
67    ///
68    /// # Examples
69    ///
70    /// ```
71    /// # use crux_core::macros::effect;
72    /// # use crux_http::HttpRequest;
73    /// # enum Event { ReceiveResponse(crux_http::Result<crux_http::Response<String>>) }
74    /// # #[effect]
75    /// # #[allow(unused)]
76    /// # enum Effect { Http(HttpRequest) }
77    /// # type Http = crux_http::command::Http<Effect, Event>;
78    /// Http::get("https://httpbin.org/get")
79    ///     .expect_string()
80    ///     .build()
81    ///     .then_send(Event::ReceiveResponse);
82    /// ```
83    pub fn get(url: impl AsRef<str>) -> command::RequestBuilder<Effect, Event> {
84        command::RequestBuilder::new(Method::GET, url.as_ref().parse().unwrap())
85    }
86
87    /// Instruct the Shell to perform a HTTP HEAD request to the provided `url`.
88    ///
89    /// The request can be configured via associated functions on the returned
90    /// [`RequestBuilder`] and then converted to a [`Command`](crux_core::Command)
91    /// with [`RequestBuilder::build`].
92    ///
93    /// # Panics
94    ///
95    /// This will panic if a malformed URL is passed.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// # use crux_core::macros::effect;
101    /// # use crux_http::HttpRequest;
102    /// # enum Event { ReceiveResponse(crux_http::Result<crux_http::Response<Vec<u8>>>) }
103    /// # #[effect]
104    /// # #[allow(unused)]
105    /// # enum Effect { Http(HttpRequest) }
106    /// # type Http = crux_http::command::Http<Effect, Event>;
107    /// Http::head("https://httpbin.org/get")
108    ///     .build()
109    ///     .then_send(Event::ReceiveResponse);
110    pub fn head(url: impl AsRef<str>) -> command::RequestBuilder<Effect, Event> {
111        command::RequestBuilder::new(Method::HEAD, url.as_ref().parse().unwrap())
112    }
113
114    /// Instruct the Shell to perform a HTTP POST request to the provided `url`.
115    ///
116    /// The request can be configured via associated functions on the returned
117    /// [`RequestBuilder`] and then converted to a [`Command`](crux_core::Command)
118    /// with [`RequestBuilder::build`].
119    ///
120    /// # Panics
121    ///
122    /// This will panic if a malformed URL is passed.
123    ///
124    /// # Examples
125    ///
126    /// ```
127    /// # use crux_core::macros::effect;
128    /// # use crux_http::HttpRequest;
129    /// # enum Event { ReceiveResponse(crux_http::Result<crux_http::Response<Vec<u8>>>) }
130    /// # #[effect]
131    /// # #[allow(unused)]
132    /// # enum Effect { Http(HttpRequest) }
133    /// # type Http = crux_http::command::Http<Effect, Event>;
134    /// Http::post("https://httpbin.org/post")
135    ///     .body_bytes(b"hello_world".to_owned())
136    ///     .build()
137    ///     .then_send(Event::ReceiveResponse);
138    pub fn post(url: impl AsRef<str>) -> command::RequestBuilder<Effect, Event> {
139        command::RequestBuilder::new(Method::POST, url.as_ref().parse().unwrap())
140    }
141
142    /// Instruct the Shell to perform a HTTP PUT request to the provided `url`.
143    ///
144    /// The request can be configured via associated functions on the returned
145    /// [`RequestBuilder`] and then converted to a [`Command`](crux_core::Command)
146    /// with [`RequestBuilder::build`].
147    ///
148    /// # Panics
149    ///
150    /// This will panic if a malformed URL is passed.
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// # use crux_core::macros::effect;
156    /// # use crux_http::HttpRequest;
157    /// # enum Event { ReceiveResponse(crux_http::Result<crux_http::Response<Vec<u8>>>) }
158    /// # #[effect]
159    /// # #[allow(unused)]
160    /// # enum Effect { Http(HttpRequest) }
161    /// # type Http = crux_http::command::Http<Effect, Event>;
162    /// Http::put("https://httpbin.org/put")
163    ///     .body_string("hello_world".to_string())
164    ///     .build()
165    ///     .then_send(Event::ReceiveResponse);
166    pub fn put(url: impl AsRef<str>) -> command::RequestBuilder<Effect, Event> {
167        command::RequestBuilder::new(Method::PUT, url.as_ref().parse().unwrap())
168    }
169
170    /// Instruct the Shell to perform a HTTP DELETE request to the provided `url`.
171    ///
172    /// The request can be configured via associated functions on the returned
173    /// [`RequestBuilder`] and then converted to a [`Command`](crux_core::Command)
174    /// with [`RequestBuilder::build`].
175    ///
176    /// # Panics
177    ///
178    /// This will panic if a malformed URL is passed.
179    ///
180    /// # Examples
181    ///
182    /// ```
183    /// # use crux_core::macros::effect;
184    /// # use crux_http::HttpRequest;
185    /// # enum Event { ReceiveResponse(crux_http::Result<crux_http::Response<Vec<u8>>>) }
186    /// # #[effect]
187    /// # #[allow(unused)]
188    /// # enum Effect { Http(HttpRequest) }
189    /// # type Http = crux_http::command::Http<Effect, Event>;
190    /// Http::delete("https://httpbin.org/delete")
191    ///     .build()
192    ///     .then_send(Event::ReceiveResponse);
193    pub fn delete(url: impl AsRef<str>) -> command::RequestBuilder<Effect, Event> {
194        command::RequestBuilder::new(Method::DELETE, url.as_ref().parse().unwrap())
195    }
196
197    /// Instruct the Shell to perform a HTTP PATCH request to the provided `url`.
198    ///
199    /// The request can be configured via associated functions on the returned
200    /// [`RequestBuilder`] and then converted to a [`Command`](crux_core::Command)
201    /// with [`RequestBuilder::build`].
202    ///
203    /// # Panics
204    ///
205    /// This will panic if a malformed URL is passed.
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// # use crux_core::macros::effect;
211    /// # use crux_http::HttpRequest;
212    /// # enum Event { ReceiveResponse(crux_http::Result<crux_http::Response<Vec<u8>>>) }
213    /// # #[effect]
214    /// # #[allow(unused)]
215    /// # enum Effect { Http(HttpRequest) }
216    /// # type Http = crux_http::command::Http<Effect, Event>;
217    /// Http::patch("https://httpbin.org/patch")
218    ///     .body_form(&[("name", "Alice")]).unwrap()
219    ///     .build()
220    ///     .then_send(Event::ReceiveResponse);
221    pub fn patch(url: impl AsRef<str>) -> command::RequestBuilder<Effect, Event> {
222        command::RequestBuilder::new(Method::PATCH, url.as_ref().parse().unwrap())
223    }
224
225    /// Instruct the Shell to perform a HTTP OPTIONS request to the provided `url`.
226    ///
227    /// The request can be configured via associated functions on the returned
228    /// [`RequestBuilder`] and then converted to a [`Command`](crux_core::Command)
229    /// with [`RequestBuilder::build`].
230    ///
231    /// # Panics
232    ///
233    /// This will panic if a malformed URL is passed.
234    ///
235    /// # Examples
236    ///
237    /// ```
238    /// # use crux_core::macros::effect;
239    /// # use crux_http::HttpRequest;
240    /// # enum Event { ReceiveResponse(crux_http::Result<crux_http::Response<Vec<u8>>>) }
241    /// # #[effect]
242    /// # #[allow(unused)]
243    /// # enum Effect { Http(HttpRequest) }
244    /// # type Http = crux_http::command::Http<Effect, Event>;
245    /// Http::options("https://httpbin.org/get")
246    ///     .build()
247    ///     .then_send(Event::ReceiveResponse);
248    pub fn options(url: impl AsRef<str>) -> command::RequestBuilder<Effect, Event> {
249        command::RequestBuilder::new(Method::OPTIONS, url.as_ref().parse().unwrap())
250    }
251
252    /// Instruct the Shell to perform a HTTP TRACE request to the provided `url`.
253    ///
254    /// The request can be configured via associated functions on the returned
255    /// [`RequestBuilder`] and then converted to a [`Command`](crux_core::Command)
256    /// with [`RequestBuilder::build`].
257    ///
258    /// # Panics
259    ///
260    /// This will panic if a malformed URL is passed.
261    ///
262    /// # Examples
263    ///
264    /// ```
265    /// # use crux_core::macros::effect;
266    /// # use crux_http::HttpRequest;
267    /// # enum Event { ReceiveResponse(crux_http::Result<crux_http::Response<Vec<u8>>>) }
268    /// # #[effect]
269    /// # #[allow(unused)]
270    /// # enum Effect { Http(HttpRequest) }
271    /// # type Http = crux_http::command::Http<Effect, Event>;
272    /// Http::trace("https://httpbin.org/get")
273    ///     .build()
274    ///     .then_send(Event::ReceiveResponse);
275    pub fn trace(url: impl AsRef<str>) -> command::RequestBuilder<Effect, Event> {
276        command::RequestBuilder::new(Method::TRACE, url.as_ref().parse().unwrap())
277    }
278
279    /// Instruct the Shell to perform a HTTP CONNECT request to the provided `url`.
280    ///
281    /// The request can be configured via associated functions on the returned
282    /// [`RequestBuilder`] and then converted to a [`Command`](crux_core::Command)
283    /// with [`RequestBuilder::build`].
284    ///
285    /// # Panics
286    ///
287    /// This will panic if a malformed URL is passed.
288    ///
289    /// # Examples
290    ///
291    /// ```
292    /// # use crux_core::macros::effect;
293    /// # use crux_http::HttpRequest;
294    /// # enum Event { ReceiveResponse(crux_http::Result<crux_http::Response<Vec<u8>>>) }
295    /// # #[effect]
296    /// # #[allow(unused)]
297    /// # enum Effect { Http(HttpRequest) }
298    /// # type Http = crux_http::command::Http<Effect, Event>;
299    /// Http::connect("https://httpbin.org/get")
300    ///     .build()
301    ///     .then_send(Event::ReceiveResponse);
302    pub fn connect(url: impl AsRef<str>) -> command::RequestBuilder<Effect, Event> {
303        command::RequestBuilder::new(Method::CONNECT, url.as_ref().parse().unwrap())
304    }
305
306    /// Instruct the Shell to perform an HTTP request to the provided `url`.
307    ///
308    /// The request can be configured via associated functions on the returned
309    /// [`RequestBuilder`] and then converted to a [`Command`](crux_core::Command)
310    /// with [`RequestBuilder::build`].
311    ///
312    /// # Panics
313    ///
314    /// This will panic if a malformed URL is passed.
315    ///
316    /// # Examples
317    ///
318    /// ```
319    /// # use crux_http::Method;
320    /// # use crux_core::macros::effect;
321    /// # use crux_http::HttpRequest;
322    /// # enum Event { ReceiveResponse(crux_http::Result<crux_http::Response<Vec<u8>>>) }
323    /// # #[effect]
324    /// # #[allow(unused)]
325    /// # enum Effect { Http(HttpRequest) }
326    /// # type Http = crux_http::command::Http<Effect, Event>;
327    /// Http::request(Method::POST, "https://httpbin.org/post".parse().unwrap())
328    ///     .body_form(&[("name", "Alice")]).unwrap()
329    ///     .build()
330    ///     .then_send(Event::ReceiveResponse);
331    pub fn request(method: Method, url: Url) -> command::RequestBuilder<Effect, Event> {
332        command::RequestBuilder::new(method, url)
333    }
334}