mochow_sdk_rust/mochow/client.rs
1/*
2 * Copyright 2024 Baidu, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11 * either express or implied. See the License for the specific language governing permissions
12 * and limitations under the License.
13 */
14
15/*
16client to connect to mochow server
17 */
18use std::time::Duration;
19
20use derive_builder::Builder;
21use reqwest::Response;
22use reqwest_middleware::{ClientBuilder, ClientWithMiddleware, RequestBuilder};
23use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
24use reqwest_tracing::TracingMiddleware;
25use serde::{Deserialize, Serialize};
26
27use crate::{auth::credentials, error::SdkError};
28
29use super::{api::*, config::*};
30
31#[derive(Debug, Clone, Builder)]
32pub struct MochowClient {
33 /// with important credential information
34 #[builder(setter(into))]
35 pub(crate) credential: credentials::Credentials,
36 /// underlying http client
37 #[builder(setter(into))]
38 pub(crate) http_client: ClientWithMiddleware,
39
40 #[builder(setter(into))]
41 pub configuration: ClientConfiguration,
42}
43
44/// every request should imple IntoRequest trait, it's just a rest request for http client
45pub trait IntoRequest {
46 fn into_request(
47 self,
48 config: &ClientConfiguration,
49 client: &ClientWithMiddleware,
50 ) -> RequestBuilder;
51}
52
53impl MochowClient {
54 /// create a new mochow client with account, api_key and endpoint
55 /// ```rust
56 /// use mochow_rust_sdk::mochow::client::MochowClient;
57 /// let client = MochowClient::new("account", "api_key", "endpoint").unwrap();
58 /// ```
59 pub fn new(account: &str, api_key: &str, endpoint: &str) -> Result<Self, SdkError> {
60 Self::new_with_configuration(
61 &ClientConfigurationBuilder::default()
62 .account(account)
63 .api_key(api_key)
64 .endpoint(endpoint)
65 .build()?,
66 )
67 }
68
69 // get the http client with config
70 fn _http_client(config: &ClientConfiguration) -> ClientWithMiddleware {
71 let retry_policy = ExponentialBackoff::builder().build_with_max_retries(config.max_retries);
72 ClientBuilder::new(reqwest::Client::new())
73 // Trace HTTP request
74 .with(TracingMiddleware::default())
75 // Retry
76 .with(RetryTransientMiddleware::new_with_policy(retry_policy))
77 .build()
78 }
79
80 /// create a new mochow client with configuration
81 /// ```rust
82 /// use mochow_rust_sdk::mochow::{config::ClientConfigurationBuilder, client::MochowClient};
83 /// let config = ClientConfigurationBuilder::default()
84 /// .account("account")
85 /// .api_key("api_key")
86 /// .endpoint("endpoint")
87 /// .build().unwrap();
88 /// let client = MochowClient::new_with_configuration(&config).unwrap();
89 /// ```
90 pub fn new_with_configuration(config: &ClientConfiguration) -> Result<Self, SdkError> {
91 let mut config = config.clone();
92 if config.account.is_empty() || config.api_key.is_empty() || config.endpoint.is_empty() {
93 return Err(SdkError::ParamsError(
94 "account, apiKey and endpoint missing for creating mochow client".to_string(),
95 ));
96 }
97 let auth = credentials::Credentials::new(&config.account, &config.api_key)?;
98 let endpoint = config.endpoint.clone();
99 let endpoint = if endpoint.starts_with("http://") || endpoint.starts_with("https://") {
100 endpoint
101 } else {
102 format!("http://{}", endpoint)
103 };
104 config.endpoint = endpoint;
105 let ret = MochowClientBuilder::default()
106 .credential(auth)
107 .http_client(Self::_http_client(&config))
108 .configuration(config)
109 .build()?;
110 Ok(ret)
111 }
112
113 /// create a database
114 /// ```rust
115 /// let _ = client.create_database("test").await?;
116 /// ```
117 pub async fn create_database(&self, data_base: &str) -> Result<CommonResponse, SdkError> {
118 let args = CreateDatabaseArgsBuilder::default()
119 .database(data_base)
120 .build()?;
121 let req = self.prepare_request(args);
122 let res = req.send_and_log().await?;
123 Ok(res.json::<CommonResponse>().await?)
124 }
125
126 /// drop the database you created, before deleting the database, all tables in the database must be deleted in advance
127 /// ```rust
128 /// let _ = client.drop_database("test").await?;
129 /// ```
130 pub async fn drop_database(&self, data_base: &str) -> Result<CommonResponse, SdkError> {
131 let args = DropDatabaseArgsBuilder::default()
132 .database(data_base)
133 .build()?;
134 let req = self.prepare_request(args);
135 let res = req.send_and_log().await?;
136 Ok(res.json::<CommonResponse>().await?)
137 }
138
139 /// list current all databases
140 /// ```rust
141 /// let ret = client.list_database("test").await?;
142 /// println!("{:?}", ret.databases);
143 /// ```
144 pub async fn list_database(&self) -> Result<ListDatabaseResponse, SdkError> {
145 let args = ListDatabaseArgsBuilder::default().build()?;
146 let req = self.prepare_request(args);
147 let res = req.send_and_log().await?;
148 Ok(res.json::<ListDatabaseResponse>().await?)
149 }
150
151 /// check if the database is exist,
152 pub async fn hash_database(&self, data_base: &str) -> Result<bool, SdkError> {
153 let list_database_resp = self.list_database().await?;
154 Ok(list_database_resp
155 .databases
156 .contains(&data_base.to_string()))
157 }
158
159 /// create table
160 /// please check the [crate::mochow::api::CreateTableArgs]
161 /// ```rust
162 /// use mochow_rust_sdk::mochow::api::{CreateTableArgsBuilder, Partition, TableSchema}
163 /// let fields = vec![];
164 /// let indexes = vec![];
165 /// let args = CreateTableArgsBuilder::default()
166 /// .database("test_db")
167 /// .table("test_table")
168 /// .description("basic test".to_string())
169 /// .replication(3 as u32)
170 /// .partition(Partition {
171 /// partition_type: PartitionType::HASH,
172 /// partition_num: 3,
173 /// })
174 /// .schema(TableSchema {
175 /// fields: fields,
176 /// indexes: indexes,
177 /// })
178 /// .build()?;
179 /// let create_table_resp = client.create_table(&args).await?;
180 /// println!("{:?}", create_table_resp);
181 /// ```
182 pub async fn create_table(&self, args: &CreateTableArgs) -> Result<CommonResponse, SdkError> {
183 let req = self.prepare_request(args.clone());
184 let res = req.send_and_log().await?;
185 Ok(res.json::<CommonResponse>().await?)
186 }
187
188 /// drop table
189 pub async fn drop_table(
190 &self,
191 data_base: &str,
192 table: &str,
193 ) -> Result<CommonResponse, SdkError> {
194 let args = DropTableArgsBuilder::default()
195 .database(data_base)
196 .table(table)
197 .build()?;
198 let req = self.prepare_request(args);
199 let res = req.send_and_log().await?;
200 Ok(res.json::<CommonResponse>().await?)
201 }
202
203 /// list table
204 pub async fn list_table(&self, data_base: &str) -> Result<ListTableResponse, SdkError> {
205 let args = ListTableArgsBuilder::default()
206 .database(data_base)
207 .build()?;
208 let req = self.prepare_request(args);
209 let res = req.send_and_log().await?;
210 Ok(res.json::<ListTableResponse>().await?)
211 }
212
213 /// has table
214 pub async fn has_table(&self, data_base: &str, table: &str) -> Result<bool, SdkError> {
215 let list_table = self.list_table(data_base).await?;
216 Ok(list_table.tables.contains(&table.to_string()))
217 }
218
219 /// descript table
220 pub async fn desc_table(
221 &self,
222 data_base: &str,
223 table: &str,
224 ) -> Result<DescriptTableResponse, SdkError> {
225 let args = DescriptTableArgsBuilder::default()
226 .database(data_base)
227 .table(table)
228 .build()?;
229 let req = self.prepare_request(args);
230 let res = req.send_and_log().await?;
231 Ok(res.json::<DescriptTableResponse>().await?)
232 }
233
234 /// add field for table, currently only supports adding scalar fields
235 /// ```rust
236 /// use mochow_rust_sdk::mochow::api::{TableSchema, FieldSchemaBuilder, AddFieldArgsBuilder};
237 /// let fields = vec![FieldSchemaBuilder::default()
238 /// .field_name("bookAlias")
239 /// .field_type("STRING")
240 /// .build()?];
241 /// let args = AddFieldArgsBuilder::default()
242 /// .database("test_db")
243 /// .table("test_table")
244 /// .schema(TableSchema{
245 /// fields: fields,
246 /// indexes: vec![],
247 /// })
248 /// .build()?;
249 /// let ret = client.add_field(&args).await?;
250 /// ```
251 pub async fn add_field(&self, args: &AddFieldArgs) -> Result<CommonResponse, SdkError> {
252 let req = self.prepare_request(args.clone());
253 let res = req.send_and_log().await?;
254 Ok(res.json::<CommonResponse>().await?)
255 }
256
257 /// show table stats
258 pub async fn show_table_stats(
259 &self,
260 data_base: &str,
261 table: &str,
262 ) -> Result<StatsTableResponse, SdkError> {
263 let args = StatsTableArgsBuilder::default()
264 .database(data_base)
265 .table(table)
266 .build()?;
267 let req = self.prepare_request(args);
268 let res = req.send_and_log().await?;
269 Ok(res.json::<StatsTableResponse>().await?)
270 }
271
272 /// alias table
273 pub async fn alias_table(
274 &self,
275 data_base: &str,
276 table: &str,
277 alias: &str,
278 ) -> Result<CommonResponse, SdkError> {
279 let args = AliasTableArgsBuilder::default()
280 .database(data_base)
281 .table(table)
282 .alias(alias)
283 .build()?;
284 let req = self.prepare_request(args);
285 let res = req.send_and_log().await?;
286 Ok(res.json::<CommonResponse>().await?)
287 }
288
289 /// unalias table
290 pub async fn unalias_table(
291 &self,
292 data_base: &str,
293 table: &str,
294 alias: &str,
295 ) -> Result<CommonResponse, SdkError> {
296 let args = UnaliasTableArgsBuilder::default()
297 .database(data_base)
298 .table(table)
299 .alias(alias)
300 .build()?;
301 let req = self.prepare_request(args);
302 let res = req.send_and_log().await?;
303 Ok(res.json::<CommonResponse>().await?)
304 }
305
306 /// create index, only support for vector index
307 /// ```rust
308 /// let indexes = vec![IndexSchemaBuilder::default()
309 /// .index_name("vector_idx")
310 /// .field("vector")
311 /// .index_type(IndexType::HNSW)
312 /// ..metric_type(MetricType::L2)
313 /// .params(VectorIndexParams::HNSW(HNSWIndexParam {
314 /// m: 16,
315 /// ef_construction: 200,
316 /// }))
317 /// .build()?];
318 /// let args = CreateIndexArgsBuilder::default()
319 /// .database("test_db")
320 /// .table("test_table")
321 /// .indexes(indexes)
322 /// .build()?;
323 /// let ret = client.create_index(&args).await?;
324 /// ```
325 pub async fn create_index(&self, args: &CreateIndexArgs) -> Result<CommonResponse, SdkError> {
326 let req = self.prepare_request(args.clone());
327 let res = req.send_and_log().await?;
328 Ok(res.json::<CommonResponse>().await?)
329 }
330
331 /// descript index
332 pub async fn desc_index(
333 &self,
334 data_base: &str,
335 table: &str,
336 index_name: &str,
337 ) -> Result<DescriptIndexResponse, SdkError> {
338 let args = DescriptIndexArgsBuilder::default()
339 .database(data_base)
340 .table(table)
341 .index_name(index_name)
342 .build()?;
343 let req = self.prepare_request(args.clone());
344 let res = req.send_and_log().await?;
345 Ok(res.json::<DescriptIndexResponse>().await?)
346 }
347
348 /// modify vector index info, only support 'autobuild' attribute
349 /// ```rust
350 /// let index = IndexSchemaBuilder::default()
351 /// .index_name("vector_idx")
352 /// .auto_build(true)
353 /// .auto_build_policy(
354 /// AutoBuildPolicyBuilder::default()
355 /// .policy_type(AutoBuildPolicyType::PERIODICAL)
356 /// .period_in_second(5000 as u64)
357 /// .build()?,
358 /// )
359 /// .build()?;
360 /// let args = ModifyIndexArgsBuilder::default()
361 /// .database("test_db")
362 /// .table("test_table")
363 /// .index(index)
364 /// .build()?;
365 /// let ret = client.modify_index(&args).await?;
366 /// ```
367 pub async fn modify_index(&self, args: &ModifyIndexArgs) -> Result<CommonResponse, SdkError> {
368 let req = self.prepare_request(args.clone());
369 let res = req.send_and_log().await?;
370 Ok(res.json::<CommonResponse>().await?)
371 }
372
373 /// rebuild index, only support for vector index
374 pub async fn rebuild_index(
375 &self,
376 data_base: &str,
377 table: &str,
378 index_name: &str,
379 ) -> Result<CommonResponse, SdkError> {
380 let args = RebuildIndexArgsBuilder::default()
381 .database(data_base)
382 .table(table)
383 .index_name(index_name)
384 .build()?;
385 let req = self.prepare_request(args);
386 let res = req.send_and_log().await?;
387 Ok(res.json::<CommonResponse>().await?)
388 }
389
390 /// delete index
391 pub async fn delete_index(
392 &self,
393 data_base: &str,
394 table: &str,
395 index_name: &str,
396 ) -> Result<CommonResponse, SdkError> {
397 let args = DeleteIndexArgsBuilder::default()
398 .database(data_base)
399 .table(table)
400 .index_name(index_name)
401 .build()?;
402 let req = self.prepare_request(args);
403 let res = req.send_and_log().await?;
404 Ok(res.json::<CommonResponse>().await?)
405 }
406
407 /// insert row, when the primary key of the record already exists, an insertion error occurs, not support insert batch atomicity
408 /// ```rust
409 /// #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
410 /// struct MyRecord {
411 /// #[serde(default)]
412 /// id: String,
413 /// #[serde(default, rename = "bookName")]
414 /// book_name: String,
415 /// #[serde(default)]
416 /// author: String,
417 /// #[serde(default)]
418 /// page: i32,
419 /// #[serde(default)]
420 /// vector: Vec<f64>,
421 /// }
422 /// // insert row with a defined struct
423 /// let args1 = InsertRowArgsBuilder::default()
424 /// .database(&TESTDATABSE.to_string())
425 /// .table(&TESTTABLE.to_string())
426 /// .rows(vec![MyRecord {
427 /// id: "0001".to_string(),
428 /// book_name: "西游记".to_string(),
429 /// author: "吴承恩".to_string(),
430 /// page: 21,
431 /// vector: vec![0.2123, 0.24, 0.213],
432 /// }])
433 /// .build()?;
434 /// // insert row with a json object
435 /// let _ret = client.insert_row(&args1).await?;
436 /// let args2 = InsertRowArgsBuilder::default()
437 /// .database(&TESTDATABSE.to_string())
438 /// .table(&TESTTABLE.to_string())
439 /// .rows(vec![serde_json::json!({
440 /// "id": "0002",
441 /// "bookName": "西游记",
442 /// "author": "吴承恩",
443 /// "page": 22,
444 /// "vector": [0.2123, 0.24, 0.213],
445 /// })])
446 /// .build()?;
447 /// let _ret = client.insert_row(&args2).await?;
448 /// ```
449 pub async fn insert_row<T: Serialize + Clone>(
450 &self,
451 args: &InsertRowArgs<T>,
452 ) -> Result<InsertRowsResponse, SdkError> {
453 let req = self.prepare_request(args.clone());
454 let res = req.send_and_log().await?;
455 Ok(res.json::<InsertRowsResponse>().await?)
456 }
457
458 /// upsert row, when the primary key of the record already exists, overwrite the old data with the new data as a whole, not support insert batch atomicity
459 /// ```
460 /// let args = UpsertRowArgsBuilder::default()
461 /// .database(&TESTDATABSE.to_string())
462 /// .table(&TESTTABLE.to_string())
463 /// .rows(vec![
464 /// serde_json::json!({
465 /// "id": "0001",
466 /// "bookName": "西游记",
467 /// "author": "吴承恩",
468 /// "page": 21,
469 /// "vector": [0.2123, 0.21, 0.213],
470 /// })
471 /// ])
472 /// .build()?;
473 /// let _ret = client.upsert_row(&args).await?;
474 /// ```
475 pub async fn upsert_row<T: Serialize + Clone>(
476 &self,
477 args: &UpsertRowArgs<T>,
478 ) -> Result<UpsertRowsResponse, SdkError> {
479 let req = self.prepare_request(args.clone());
480 let res = req.send_and_log().await?;
481 Ok(res.json::<UpsertRowsResponse>().await?)
482 }
483
484 /// update row, update the value of one or more scalar fields in a specified record
485 /// ```rust
486 /// let args = UpdateRowArgsBuilder::default()
487 /// .database(&TESTDATABSE.to_string())
488 /// .table(&TESTTABLE.to_string())
489 /// .primary_key(serde_json::json!({
490 /// "id": "0001",
491 /// }))
492 /// .update(serde_json::json!({
493 /// "bookName": "红楼梦",
494 /// "author": "曹雪芹",
495 /// "page": 100,
496 /// }))
497 /// .build()?;
498 /// let _ret = client.update_row(&args).await?;
499 /// ```
500 pub async fn update_row(&self, args: &UpdateRowArgs) -> Result<CommonResponse, SdkError> {
501 let req = self.prepare_request(args.clone());
502 let res = req.send_and_log().await?;
503 Ok(res.json::<CommonResponse>().await?)
504 }
505
506 /// delete rows, you can delete multiple records by primary key, or filter the records to be deleted
507 /// ```rust
508 /// let args = DeleteRowArgsBuilder::default()
509 /// .database(&TESTDATABSE.to_string())
510 /// .table(&TESTTABLE.to_string())
511 /// .primary_key(serde_json::json!({
512 /// "id": "0001",
513 /// }))
514 /// .filter("page >= 22")
515 /// .build()?;
516 /// let _ret = UTCLIENT.delete_rows(&args).await?;
517 /// ```
518 pub async fn delete_rows(&self, args: &DeleteRowArgs) -> Result<CommonResponse, SdkError> {
519 let req = self.prepare_request(args.clone());
520 let res = req.send_and_log().await?;
521 Ok(res.json::<CommonResponse>().await?)
522 }
523
524 /// query row, query single row by primary key
525 /// ```rust
526 /// let args = QueryRowArgsBuilder::default()
527 /// .database(&TESTDATABSE.to_string())
528 /// .table(&TESTTABLE.to_string())
529 /// .primary_key(serde_json::json!({
530 /// "id": "0001",
531 /// }))
532 /// .projections(vec!["id".to_string(), "bookName".to_string()])
533 /// .retrieve_vector(false)
534 /// .build()?;
535 /// let query_ret: QueryRowsResponse<MyRecord> = UTCLIENT.query_row(&args).await?;
536 /// println!("query_row ret: {:?}", query_ret.row);
537 /// let row1 = query_ret.row;
538 /// let query_ret: QueryRowsResponse<serde_json::Value> = UTCLIENT.query_row(&args).await?;
539 /// println!("query_row ret: {:?}", query_ret.row);
540 /// // convert json value to struct
541 /// let row2 = serde_json::from_value(query_ret.row)?;
542 /// assert_eq!(row1, row2);
543 /// ```
544 pub async fn query_row<T>(&self, args: &QueryRowArgs) -> Result<QueryRowsResponse<T>, SdkError>
545 where
546 T: for<'de> Deserialize<'de>,
547 {
548 let req = self.prepare_request(args.clone());
549 let res = req.send_and_log().await?;
550 Ok(res.json::<QueryRowsResponse<T>>().await?)
551 }
552
553 /// search rows
554 /// basing ann search of vector fields, support filter by scalar fields
555 /// ```rust
556 /// let search_args = SearchRowsArgsBuilder::default()
557 /// .database(&TESTDATABSE.to_string())
558 /// .table(&TESTTABLE.to_string())
559 /// .anns(
560 /// AnnsSearchParamsBuilder::default()
561 /// .vector_field("vector")
562 /// .vector_floats(vec![0.3123, 0.43, 0.213])
563 /// .params(VectorSearchParams::HNSW(HNSWSearchParams {
564 /// ef: 200,
565 /// limit: 10,
566 /// distance_far: None,
567 /// distance_near: None,
568 /// pruning: false,
569 /// }))
570 /// .filter("bookName = '三国演义'")
571 /// .build()?,
572 /// )
573 /// .retrieve_vector(true)
574 /// .build()?;
575 /// let ret: SearchRowsResponse<serde_json::Value> = client.search_rows(&search_args).await?;
576 /// ```
577 pub async fn search_rows<T>(
578 &self,
579 args: &SearchRowsArgs,
580 ) -> Result<SearchRowsResponse<T>, SdkError>
581 where
582 T: for<'de> Deserialize<'de>,
583 {
584 let req = self.prepare_request(args.clone());
585 let res = req.send_and_log().await?;
586 Ok(res.json::<SearchRowsResponse<T>>().await?)
587 }
588
589 /// select rows
590 /// filter records by scalar fields
591 /// ```rust
592 /// let mut args = SelectRowsArgsBuilder::default()
593 /// .database(&TESTDATABSE.to_string())
594 /// .table(&TESTTABLE.to_string())
595 /// .projections(vec![
596 /// "id".to_string(),
597 /// "bookName".to_string(),
598 /// "page".to_string(),
599 /// ])
600 /// .filter("page > 21")
601 /// .limit(1 as u32)
602 /// .build()?;
603 /// loop {
604 /// let ret: SelectRowsResponse<serde_json::Value> = client.select_rows(&args).await?;
605 /// println!("select_rows ret: {:?}", ret);
606 /// if !ret.is_truncated {
607 /// break;
608 /// } else {
609 /// args.marker = Some(ret.next_marker);
610 /// }
611 /// }
612 /// ```
613 pub async fn select_rows<T>(
614 &self,
615 args: &SelectRowsArgs,
616 ) -> Result<SelectRowsResponse<T>, SdkError>
617 where
618 T: for<'de> Deserialize<'de>,
619 {
620 let req = self.prepare_request(args.clone());
621 let res = req.send_and_log().await?;
622 Ok(res.json::<SelectRowsResponse<T>>().await?)
623 }
624
625 /// batch search rows
626 /// 1. basing ann search of vector fields, support filter by scalar fields
627 /// 2. support batch query
628 /// ```rust
629 /// let batch_ann_params = BatchAnnsSearchParamsBuilder::default()
630 /// .vector_field("vector")
631 /// .vector_floats(vec![vec![0.3123, 0.43, 0.213], vec![0.5512, 0.33, 0.43]])
632 /// .params(VectorSearchParams::HNSW(HNSWSearchParams {
633 /// ef: 200,
634 /// limit: 10,
635 /// distance_far: None,
636 /// distance_near: None,
637 /// pruning: false,
638 /// }))
639 /// .filter("bookName = '三国演义'")
640 /// .build()?;
641 /// let batch_search_args = BatchSearchRowsArgsBuilder::default()
642 /// .database(&TESTDATABSE.to_string())
643 /// .table(&TESTTABLE.to_string())
644 /// .anns(batch_ann_params)
645 /// .retrieve_vector(true)
646 /// .build()?;
647 /// let batch_rets: BatchSearchRowsResponse<serde_json::Value> =
648 /// UTCLIENT.batch_search_rows(&batch_search_args).await?;
649 /// for (i, bs) in batch_rets.results.iter().enumerate() {
650 /// println!("batch: {}, {:?}", i, bs.search_vector_floats);
651 /// for (j, ss) in bs.rows.iter().enumerate() {
652 /// println!("{}, {:?}", j, ss);
653 /// }
654 /// }
655 /// ```
656 pub async fn batch_search_rows<T>(
657 &self,
658 args: &BatchSearchRowsArgs,
659 ) -> Result<BatchSearchRowsResponse<T>, SdkError>
660 where
661 T: for<'de> Deserialize<'de>,
662 {
663 let req = self.prepare_request(args.clone());
664 let res = req.send_and_log().await?;
665 Ok(res.json::<BatchSearchRowsResponse<T>>().await?)
666 }
667
668 fn prepare_request(&self, req: impl IntoRequest) -> RequestBuilder {
669 let mut req = req.into_request(&self.configuration, &self.http_client);
670 if !self.credential.token.is_empty() {
671 req = req.bearer_auth(&self.credential.token)
672 };
673 for (key, value) in &self.configuration.get_request_headers() {
674 req = req.header(key, value);
675 }
676 req.timeout(Duration::from_secs(self.configuration.time_out_seconds))
677 }
678}
679
680trait SendAndLog {
681 async fn send_and_log(self) -> Result<Response, SdkError>;
682}
683
684impl SendAndLog for RequestBuilder {
685 async fn send_and_log(self) -> Result<Response, SdkError> {
686 let res = self.send().await?;
687 let status_code = res.status();
688 let request_id = if let Some(header_value) = res.headers().get("Request-ID") {
689 if let Ok(request_id) = header_value.to_str() {
690 request_id.to_string()
691 } else {
692 "".to_string()
693 }
694 } else {
695 "".to_string()
696 };
697 if status_code.is_client_error() || status_code.is_server_error() {
698 // try to parse service error message, if failed, use default error message
699 let service_msg = res.json::<CommonResponse>().await;
700 let msg = match service_msg {
701 Ok(msg) => msg,
702 Err(e) => CommonResponse {
703 code: -1,
704 msg: format!("Service json error message decode failed: {}", e),
705 },
706 };
707 return Err(SdkError::ServiceError(ServiceError {
708 status_code: status_code.as_u16() as i32,
709 request_id: request_id,
710 server_code: msg.clone().code.into(),
711 resp: msg,
712 }));
713 }
714 Ok(res)
715 }
716}