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