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