20
20
mod client_request;
21
21
mod precondition;
22
22
23
+ use crate :: {
24
+ error:: ClientError ,
25
+ event:: { Event , EventCandidate , ManagementEvent } ,
26
+ } ;
23
27
use client_request:: {
24
- ClientRequest , OneShotRequest , PingRequest , VerifyApiTokenRequest , WriteEventsRequest ,
28
+ ClientRequest , ListEventTypesRequest , ListSubjectsRequest , OneShotRequest , PingRequest ,
29
+ RegisterEventSchemaRequest , StreamingRequest , VerifyApiTokenRequest , WriteEventsRequest ,
30
+ list_event_types:: EventType ,
25
31
} ;
26
-
32
+ use futures :: Stream ;
27
33
pub use precondition:: Precondition ;
28
34
use reqwest;
29
35
use url:: Url ;
30
36
31
- use crate :: {
32
- error:: ClientError ,
33
- event:: { Event , EventCandidate } ,
34
- } ;
35
-
36
37
/// Client for an [EventsourcingDB](https://www.eventsourcingdb.io/) instance.
37
38
#[ derive( Debug ) ]
38
39
pub struct Client {
39
40
base_url : Url ,
40
41
api_token : String ,
41
- client : reqwest:: Client ,
42
+ reqwest : reqwest:: Client ,
42
43
}
43
44
44
45
impl Client {
@@ -47,7 +48,7 @@ impl Client {
47
48
Client {
48
49
base_url,
49
50
api_token : api_token. into ( ) ,
50
- client : reqwest:: Client :: new ( ) ,
51
+ reqwest : reqwest:: Client :: new ( ) ,
51
52
}
52
53
}
53
54
@@ -93,8 +94,8 @@ impl Client {
93
94
. map_err ( ClientError :: URLParseError ) ?;
94
95
95
96
let request = match endpoint. method ( ) {
96
- reqwest:: Method :: GET => self . client . get ( url) ,
97
- reqwest:: Method :: POST => self . client . post ( url) ,
97
+ reqwest:: Method :: GET => self . reqwest . get ( url) ,
98
+ reqwest:: Method :: POST => self . reqwest . post ( url) ,
98
99
_ => return Err ( ClientError :: InvalidRequestMethod ) ,
99
100
}
100
101
. header ( "Authorization" , format ! ( "Bearer {}" , self . api_token) ) ;
@@ -132,6 +133,28 @@ impl Client {
132
133
}
133
134
}
134
135
136
+ /// Utility function to request an endpoint of the API as a stream.
137
+ ///
138
+ /// This means, that the response is streamed and returned as a stream of values.
139
+ ///
140
+ /// # Errors
141
+ /// This function will return an error if the request fails or if the URL is invalid.
142
+ async fn request_streaming < R : StreamingRequest > (
143
+ & self ,
144
+ endpoint : R ,
145
+ ) -> Result < impl Stream < Item = Result < R :: ItemType , ClientError > > , ClientError > {
146
+ let response = self . build_request ( & endpoint) ?. send ( ) . await ?;
147
+
148
+ if response. status ( ) . is_success ( ) {
149
+ Ok ( endpoint. build_stream ( response) )
150
+ } else {
151
+ Err ( ClientError :: DBApiError (
152
+ response. status ( ) ,
153
+ response. text ( ) . await . unwrap_or_default ( ) ,
154
+ ) )
155
+ }
156
+ }
157
+
135
158
/// Pings the DB instance to check if it is reachable.
136
159
///
137
160
/// ```
@@ -174,6 +197,130 @@ impl Client {
174
197
Ok ( ( ) )
175
198
}
176
199
200
+ /// Registers an event schema with the DB instance.
201
+ ///
202
+ /// ```
203
+ /// use eventsourcingdb_client_rust::event::EventCandidate;
204
+ /// use futures::StreamExt;
205
+ /// # use serde_json::json;
206
+ /// # tokio_test::block_on(async {
207
+ /// # let container = eventsourcingdb_client_rust::container::Container::start_default().await.unwrap();
208
+ /// let db_url = "http://localhost:3000/";
209
+ /// let api_token = "secrettoken";
210
+ /// # let db_url = container.get_base_url().await.unwrap();
211
+ /// # let api_token = container.get_api_token();
212
+ /// let client = eventsourcingdb_client_rust::client::Client::new(db_url, api_token);
213
+ /// let event_type = "io.eventsourcingdb.test";
214
+ /// let schema = json!({
215
+ /// "type": "object",
216
+ /// "properties": {
217
+ /// "id": {
218
+ /// "type": "string"
219
+ /// },
220
+ /// "name": {
221
+ /// "type": "string"
222
+ /// }
223
+ /// },
224
+ /// "required": ["id", "name"]
225
+ /// });
226
+ /// client.register_event_schema(event_type, &schema).await.expect("Failed to list event types");
227
+ /// # })
228
+ /// ```
229
+ ///
230
+ /// # Errors
231
+ /// This function will return an error if the request fails or if the provided schema is invalid.
232
+ pub async fn register_event_schema (
233
+ & self ,
234
+ event_type : & str ,
235
+ schema : & serde_json:: Value ,
236
+ ) -> Result < ManagementEvent , ClientError > {
237
+ self . request_oneshot ( RegisterEventSchemaRequest :: try_new ( event_type, schema) ?)
238
+ . await
239
+ }
240
+
241
+ /// List all subjects in the DB instance.
242
+ ///
243
+ /// To get all subjects in the DB, just pass `None` as the `base_subject`.
244
+ /// ```
245
+ /// use eventsourcingdb_client_rust::event::EventCandidate;
246
+ /// use futures::StreamExt;
247
+ /// # use serde_json::json;
248
+ /// # tokio_test::block_on(async {
249
+ /// # let container = eventsourcingdb_client_rust::container::Container::start_default().await.unwrap();
250
+ /// let db_url = "http://localhost:3000/";
251
+ /// let api_token = "secrettoken";
252
+ /// # let db_url = container.get_base_url().await.unwrap();
253
+ /// # let api_token = container.get_api_token();
254
+ /// let client = eventsourcingdb_client_rust::client::Client::new(db_url, api_token);
255
+ /// let mut subject_stream = client.list_subjects(None).await.expect("Failed to list event types");
256
+ /// while let Some(subject) = subject_stream.next().await {
257
+ /// println!("Found Type {}", subject.expect("Error while reading types"));
258
+ /// }
259
+ /// # })
260
+ /// ```
261
+ ///
262
+ /// To get all subjects under /test in the DB, just pass `Some("/test")` as the `base_subject`.
263
+ /// ```
264
+ /// use eventsourcingdb_client_rust::event::EventCandidate;
265
+ /// use futures::StreamExt;
266
+ /// # use serde_json::json;
267
+ /// # tokio_test::block_on(async {
268
+ /// # let container = eventsourcingdb_client_rust::container::Container::start_default().await.unwrap();
269
+ /// let db_url = "http://localhost:3000/";
270
+ /// let api_token = "secrettoken";
271
+ /// # let db_url = container.get_base_url().await.unwrap();
272
+ /// # let api_token = container.get_api_token();
273
+ /// let client = eventsourcingdb_client_rust::client::Client::new(db_url, api_token);
274
+ /// let mut subject_stream = client.list_subjects(Some("/test")).await.expect("Failed to list event types");
275
+ /// while let Some(subject) = subject_stream.next().await {
276
+ /// println!("Found Type {}", subject.expect("Error while reading types"));
277
+ /// }
278
+ /// # })
279
+ /// ```
280
+ ///
281
+ /// # Errors
282
+ /// This function will return an error if the request fails or if the URL is invalid.
283
+ pub async fn list_subjects (
284
+ & self ,
285
+ base_subject : Option < & str > ,
286
+ ) -> Result < impl Stream < Item = Result < String , ClientError > > , ClientError > {
287
+ let response = self
288
+ . request_streaming ( ListSubjectsRequest {
289
+ base_subject : base_subject. unwrap_or ( "/" ) ,
290
+ } )
291
+ . await ?;
292
+ Ok ( response)
293
+ }
294
+
295
+ /// List all event types in the DB instance.
296
+ ///
297
+ /// ```
298
+ /// use eventsourcingdb_client_rust::event::EventCandidate;
299
+ /// use futures::StreamExt;
300
+ /// # use serde_json::json;
301
+ /// # tokio_test::block_on(async {
302
+ /// # let container = eventsourcingdb_client_rust::container::Container::start_default().await.unwrap();
303
+ /// let db_url = "http://localhost:3000/";
304
+ /// let api_token = "secrettoken";
305
+ /// # let db_url = container.get_base_url().await.unwrap();
306
+ /// # let api_token = container.get_api_token();
307
+ /// let client = eventsourcingdb_client_rust::client::Client::new(db_url, api_token);
308
+ /// let mut type_stream = client.list_event_types().await.expect("Failed to list event types");
309
+ /// while let Some(ty) = type_stream.next().await {
310
+ /// println!("Found Type {}", ty.expect("Error while reading types").name);
311
+ /// }
312
+ /// # })
313
+ /// ```
314
+ ///
315
+ /// # Errors
316
+ /// This function will return an error if the request fails or if the URL is invalid.
317
+ pub async fn list_event_types (
318
+ & self ,
319
+ ) -> Result < impl Stream < Item = Result < EventType , ClientError > > , ClientError > {
320
+ let response = self . request_streaming ( ListEventTypesRequest ) . await ?;
321
+ Ok ( response)
322
+ }
323
+
177
324
/// Writes events to the DB instance.
178
325
///
179
326
/// ```
0 commit comments