1#![allow(clippy::derive_partial_eq_without_eq)]
106#![allow(clippy::too_many_arguments)]
107#![allow(clippy::nonstandard_macro_braces)]
108#![allow(clippy::large_enum_variant)]
109#![allow(clippy::tabs_in_doc_comments)]
110#![allow(missing_docs)]
111#![cfg_attr(docsrs, feature(doc_cfg))]
112
113pub mod asps;
114pub mod channels;
115pub mod chromeosdevices;
116pub mod customer;
117pub mod customers;
118pub mod domain_aliases;
119pub mod domains;
120pub mod groups;
121pub mod members;
122pub mod mobiledevices;
123pub mod orgunits;
124pub mod privileges;
125pub mod resources;
126pub mod role_assignments;
127pub mod roles;
128pub mod schemas;
129pub mod tokens;
130pub mod two_step_verification;
131pub mod types;
132pub mod users;
133#[doc(hidden)]
134pub mod utils;
135pub mod verification_codes;
136
137pub use reqwest::{header::HeaderMap, StatusCode};
138
139#[derive(Debug)]
140pub struct Response<T> {
141 pub status: reqwest::StatusCode,
142 pub headers: reqwest::header::HeaderMap,
143 pub body: T,
144}
145
146impl<T> Response<T> {
147 pub fn new(status: reqwest::StatusCode, headers: reqwest::header::HeaderMap, body: T) -> Self {
148 Self {
149 status,
150 headers,
151 body,
152 }
153 }
154}
155
156type ClientResult<T> = Result<T, ClientError>;
157
158use thiserror::Error;
159
160#[derive(Debug, Error)]
162pub enum ClientError {
163 #[error("Refresh AuthToken is empty")]
166 EmptyRefreshToken,
167 #[error(transparent)]
169 FromUtf8Error(#[from] std::string::FromUtf8Error),
170 #[error(transparent)]
172 UrlParserError(#[from] url::ParseError),
173 #[error(transparent)]
175 SerdeJsonError(#[from] serde_json::Error),
176 #[error(transparent)]
178 ReqwestError(#[from] reqwest::Error),
179 #[error(transparent)]
181 InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
182 #[cfg(feature = "middleware")]
183 #[error(transparent)]
185 ReqwestMiddleWareError(#[from] reqwest_middleware::Error),
186 #[error("HTTP Error. Code: {status}, message: {error}")]
188 HttpError {
189 status: http::StatusCode,
190 headers: reqwest::header::HeaderMap,
191 error: String,
192 },
193}
194
195pub const FALLBACK_HOST: &str = "https://www.googleapis.com";
196
197mod progenitor_support {
198 use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
199
200 const PATH_SET: &AsciiSet = &CONTROLS
201 .add(b' ')
202 .add(b'"')
203 .add(b'#')
204 .add(b'<')
205 .add(b'>')
206 .add(b'?')
207 .add(b'`')
208 .add(b'{')
209 .add(b'}');
210
211 #[allow(dead_code)]
212 pub(crate) fn encode_path(pc: &str) -> String {
213 utf8_percent_encode(pc, PATH_SET).to_string()
214 }
215}
216
217#[derive(Debug, Default)]
218pub(crate) struct Message {
219 pub body: Option<reqwest::Body>,
220 pub content_type: Option<String>,
221}
222
223use std::convert::TryInto;
224use std::env;
225use std::ops::Add;
226use std::sync::Arc;
227use std::time::{Duration, Instant};
228use tokio::sync::RwLock;
229
230const TOKEN_ENDPOINT: &str = "https://oauth2.googleapis.com/token";
231const USER_CONSENT_ENDPOINT: &str = "https://accounts.google.com/o/oauth2/v2/auth";
232
233#[derive(Debug, Default, Clone)]
234pub struct RootDefaultServer {}
235
236impl RootDefaultServer {
237 pub fn default_url(&self) -> &str {
238 "https://www.googleapis.com"
239 }
240}
241
242#[derive(Clone)]
244pub struct Client {
245 host: String,
246 host_override: Option<String>,
247 token: Arc<RwLock<InnerToken>>,
248 client_id: String,
249 client_secret: String,
250 redirect_uri: String,
251
252 auto_refresh: bool,
253 #[cfg(feature = "middleware")]
254 client: reqwest_middleware::ClientWithMiddleware,
255 #[cfg(not(feature = "middleware"))]
256 client: reqwest::Client,
257}
258
259use schemars::JsonSchema;
260use serde::{Deserialize, Serialize};
261
262#[derive(Debug, JsonSchema, Clone, Default, Serialize, Deserialize)]
263pub struct AccessToken {
264 #[serde(
265 default,
266 skip_serializing_if = "String::is_empty",
267 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
268 )]
269 pub token_type: String,
270
271 #[serde(
272 default,
273 skip_serializing_if = "String::is_empty",
274 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
275 )]
276 pub access_token: String,
277 #[serde(default)]
278 pub expires_in: i64,
279
280 #[serde(
281 default,
282 skip_serializing_if = "String::is_empty",
283 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
284 )]
285 pub refresh_token: String,
286 #[serde(default, alias = "x_refresh_token_expires_in")]
287 pub refresh_token_expires_in: i64,
288
289 #[serde(
290 default,
291 skip_serializing_if = "String::is_empty",
292 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
293 )]
294 pub scope: String,
295}
296
297const REFRESH_THRESHOLD: Duration = Duration::from_secs(60);
301
302#[derive(Debug, Clone)]
303struct InnerToken {
304 access_token: String,
305 refresh_token: String,
306 expires_at: Option<Instant>,
307}
308
309impl Client {
310 pub fn new<I, K, R, T, Q>(
316 client_id: I,
317 client_secret: K,
318 redirect_uri: R,
319 token: T,
320 refresh_token: Q,
321 ) -> Self
322 where
323 I: ToString,
324 K: ToString,
325 R: ToString,
326 T: ToString,
327 Q: ToString,
328 {
329 let retry_policy =
331 reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
332 let client = reqwest::Client::builder()
333 .redirect(reqwest::redirect::Policy::none())
334 .build();
335 match client {
336 Ok(c) => {
337 #[cfg(feature = "middleware")]
338 let client = {
339 reqwest_middleware::ClientBuilder::new(c)
340 .with(reqwest_tracing::TracingMiddleware::default())
342 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
344 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
345 |req: &reqwest::Request| req.try_clone().is_some(),
346 ))
347 .build()
348 };
349 #[cfg(not(feature = "middleware"))]
350 let client = c;
351
352 let host = RootDefaultServer::default().default_url().to_string();
353
354 Client {
355 host,
356 host_override: None,
357 client_id: client_id.to_string(),
358 client_secret: client_secret.to_string(),
359 redirect_uri: redirect_uri.to_string(),
360 token: Arc::new(RwLock::new(InnerToken {
361 access_token: token.to_string(),
362 refresh_token: refresh_token.to_string(),
363 expires_at: None,
364 })),
365
366 auto_refresh: false,
367 client,
368 }
369 }
370 Err(e) => panic!("creating reqwest client failed: {:?}", e),
371 }
372 }
373
374 pub fn set_auto_access_token_refresh(&mut self, enabled: bool) -> &mut Self {
376 self.auto_refresh = enabled;
377 self
378 }
379
380 pub async fn set_expires_at(&self, expires_at: Option<Instant>) -> &Self {
386 self.token.write().await.expires_at = expires_at;
387 self
388 }
389
390 pub async fn expires_at(&self) -> Option<Instant> {
393 self.token.read().await.expires_at
394 }
395
396 pub async fn set_expires_in(&self, expires_in: i64) -> &Self {
399 self.token.write().await.expires_at = Self::compute_expires_at(expires_in);
400 self
401 }
402
403 pub async fn expires_in(&self) -> Option<Duration> {
406 self.token
407 .read()
408 .await
409 .expires_at
410 .map(|i| i.duration_since(Instant::now()))
411 }
412
413 pub async fn is_expired(&self) -> Option<bool> {
416 self.token
417 .read()
418 .await
419 .expires_at
420 .map(|expiration| expiration <= Instant::now())
421 }
422
423 fn compute_expires_at(expires_in: i64) -> Option<Instant> {
424 let seconds_valid = expires_in
425 .try_into()
426 .ok()
427 .map(Duration::from_secs)
428 .and_then(|dur| dur.checked_sub(REFRESH_THRESHOLD))
429 .or_else(|| Some(Duration::from_secs(0)));
430
431 seconds_valid.map(|seconds_valid| Instant::now().add(seconds_valid))
432 }
433
434 pub fn with_host_override<H>(&mut self, host: H) -> &mut Self
436 where
437 H: ToString,
438 {
439 self.host_override = Some(host.to_string());
440 self
441 }
442
443 pub fn remove_host_override(&mut self) -> &mut Self {
445 self.host_override = None;
446 self
447 }
448
449 pub fn get_host_override(&self) -> Option<&str> {
450 self.host_override.as_deref()
451 }
452
453 pub(crate) fn url(&self, path: &str, host: Option<&str>) -> String {
454 format!(
455 "{}{}",
456 self.get_host_override()
457 .or(host)
458 .unwrap_or(self.host.as_str()),
459 path
460 )
461 }
462
463 pub async fn new_from_env<T, R>(token: T, refresh_token: R) -> Self
474 where
475 T: ToString,
476 R: ToString,
477 {
478 use base64::{engine::general_purpose::STANDARD, Engine};
479
480 let google_key = env::var("GOOGLE_KEY_ENCODED").unwrap_or_default();
481 let decoded_google_key = STANDARD.decode(google_key).unwrap();
482 let secret = yup_oauth2::parse_application_secret(decoded_google_key)
483 .expect("failed to read from google credential env var");
484
485 let client = reqwest::Client::builder()
486 .redirect(reqwest::redirect::Policy::none())
487 .build();
488 let retry_policy =
489 reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
490
491 match client {
492 Ok(c) => {
493 #[cfg(feature = "middleware")]
494 let client = {
495 reqwest_middleware::ClientBuilder::new(c)
496 .with(reqwest_tracing::TracingMiddleware::default())
498 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
500 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
501 |req: &reqwest::Request| req.try_clone().is_some(),
502 ))
503 .build()
504 };
505 #[cfg(not(feature = "middleware"))]
506 let client = c;
507 let host = RootDefaultServer::default().default_url().to_string();
508
509 Client {
510 host,
511 host_override: None,
512 client_id: secret.client_id.to_string(),
513 client_secret: secret.client_secret.to_string(),
514 redirect_uri: secret.redirect_uris[0].to_string(),
515 token: Arc::new(RwLock::new(InnerToken {
516 access_token: token.to_string(),
517 refresh_token: refresh_token.to_string(),
518 expires_at: None,
519 })),
520 auto_refresh: false,
521 client,
522 }
523 }
524 Err(e) => panic!("creating reqwest client failed: {:?}", e),
525 }
526 }
527
528 pub fn user_consent_url(&self, scopes: &[String]) -> String {
531 let state = uuid::Uuid::new_v4();
532
533 let url = format!(
534 "{}?client_id={}&access_type=offline&response_type=code&redirect_uri={}&state={}",
535 USER_CONSENT_ENDPOINT, self.client_id, self.redirect_uri, state
536 );
537
538 if scopes.is_empty() {
539 return url;
540 }
541
542 format!("{}&scope={}", url, scopes.join(" "))
544 }
545
546 pub async fn refresh_access_token(&self) -> ClientResult<AccessToken> {
549 let response = {
550 let refresh_token = &self.token.read().await.refresh_token;
551
552 if refresh_token.is_empty() {
553 return Err(ClientError::EmptyRefreshToken);
554 }
555
556 let mut headers = reqwest::header::HeaderMap::new();
557 headers.append(
558 reqwest::header::ACCEPT,
559 reqwest::header::HeaderValue::from_static("application/json"),
560 );
561
562 let params = [
563 ("grant_type", "refresh_token"),
564 ("refresh_token", refresh_token),
565 ("client_id", &self.client_id),
566 ("client_secret", &self.client_secret),
567 ("redirect_uri", &self.redirect_uri),
568 ];
569 let client = reqwest::Client::new();
570 client
571 .post(TOKEN_ENDPOINT)
572 .headers(headers)
573 .form(¶ms)
574 .basic_auth(&self.client_id, Some(&self.client_secret))
575 .send()
576 .await?
577 };
578
579 let t: AccessToken = response.json().await?;
581
582 let refresh_token = self.token.read().await.refresh_token.clone();
583
584 *self.token.write().await = InnerToken {
585 access_token: t.access_token.clone(),
586 refresh_token,
587 expires_at: Self::compute_expires_at(t.expires_in),
588 };
589
590 Ok(t)
591 }
592
593 pub async fn get_access_token(&mut self, code: &str, state: &str) -> ClientResult<AccessToken> {
596 let mut headers = reqwest::header::HeaderMap::new();
597 headers.append(
598 reqwest::header::ACCEPT,
599 reqwest::header::HeaderValue::from_static("application/json"),
600 );
601
602 let params = [
603 ("grant_type", "authorization_code"),
604 ("code", code),
605 ("client_id", &self.client_id),
606 ("client_secret", &self.client_secret),
607 ("redirect_uri", &self.redirect_uri),
608 ("state", state),
609 ];
610 let client = reqwest::Client::new();
611 let resp = client
612 .post(TOKEN_ENDPOINT)
613 .headers(headers)
614 .form(¶ms)
615 .basic_auth(&self.client_id, Some(&self.client_secret))
616 .send()
617 .await?;
618
619 let t: AccessToken = resp.json().await?;
621
622 *self.token.write().await = InnerToken {
623 access_token: t.access_token.clone(),
624 refresh_token: t.refresh_token.clone(),
625 expires_at: Self::compute_expires_at(t.expires_in),
626 };
627
628 Ok(t)
629 }
630
631 async fn url_and_auth(&self, uri: &str) -> ClientResult<(reqwest::Url, Option<String>)> {
632 let parsed_url = uri.parse::<reqwest::Url>()?;
633
634 let auth = format!("Bearer {}", self.token.read().await.access_token);
635 Ok((parsed_url, Some(auth)))
636 }
637
638 async fn make_request(
639 &self,
640 method: &reqwest::Method,
641 uri: &str,
642 message: Message,
643 ) -> ClientResult<reqwest::Request> {
644 let (url, auth) = self.url_and_auth(uri).await?;
645
646 let instance = <&Client>::clone(&self);
647
648 let mut req = instance.client.request(method.clone(), url);
649
650 req = req.header(
652 reqwest::header::ACCEPT,
653 reqwest::header::HeaderValue::from_static("application/json"),
654 );
655
656 if let Some(content_type) = &message.content_type {
657 req = req.header(
658 reqwest::header::CONTENT_TYPE,
659 reqwest::header::HeaderValue::from_str(content_type).unwrap(),
660 );
661 } else {
662 req = req.header(
663 reqwest::header::CONTENT_TYPE,
664 reqwest::header::HeaderValue::from_static("application/json"),
665 );
666 }
667
668 if let Some(auth_str) = auth {
669 req = req.header(http::header::AUTHORIZATION, &*auth_str);
670 }
671
672 if let Some(body) = message.body {
673 req = req.body(body);
674 }
675
676 Ok(req.build()?)
677 }
678
679 async fn request_raw(
680 &self,
681 method: reqwest::Method,
682 uri: &str,
683 message: Message,
684 ) -> ClientResult<reqwest::Response> {
685 if self.auto_refresh {
686 let expired = self.is_expired().await;
687
688 match expired {
689 Some(true) => {
692 self.refresh_access_token().await?;
693 }
694
695 Some(false) => (),
700
701 None => (),
709 }
710 }
711
712 let req = self.make_request(&method, uri, message).await?;
713 let resp = self.client.execute(req).await?;
714
715 Ok(resp)
716 }
717
718 async fn request<Out>(
719 &self,
720 method: reqwest::Method,
721 uri: &str,
722 message: Message,
723 ) -> ClientResult<crate::Response<Out>>
724 where
725 Out: serde::de::DeserializeOwned + 'static + Send,
726 {
727 let response = self.request_raw(method, uri, message).await?;
728
729 let status = response.status();
730 let headers = response.headers().clone();
731
732 let response_body = response.bytes().await?;
733
734 if status.is_success() {
735 log::debug!("Received successful response. Read payload.");
736 let parsed_response = if status == http::StatusCode::NO_CONTENT
737 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
738 {
739 serde_json::from_str("null")?
740 } else {
741 serde_json::from_slice::<Out>(&response_body)?
742 };
743 Ok(crate::Response::new(status, headers, parsed_response))
744 } else {
745 let error = if response_body.is_empty() {
746 ClientError::HttpError {
747 status,
748 headers,
749 error: "empty response".into(),
750 }
751 } else {
752 ClientError::HttpError {
753 status,
754 headers,
755 error: String::from_utf8_lossy(&response_body).into(),
756 }
757 };
758
759 Err(error)
760 }
761 }
762
763 async fn request_with_links<Out>(
764 &self,
765 method: http::Method,
766 uri: &str,
767 message: Message,
768 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Out>)>
769 where
770 Out: serde::de::DeserializeOwned + 'static + Send,
771 {
772 let response = self.request_raw(method, uri, message).await?;
773
774 let status = response.status();
775 let headers = response.headers().clone();
776 let link = response
777 .headers()
778 .get(http::header::LINK)
779 .and_then(|l| l.to_str().ok())
780 .and_then(|l| parse_link_header::parse(l).ok())
781 .as_ref()
782 .and_then(crate::utils::next_link);
783
784 let response_body = response.bytes().await?;
785
786 if status.is_success() {
787 log::debug!("Received successful response. Read payload.");
788
789 let parsed_response = if status == http::StatusCode::NO_CONTENT
790 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
791 {
792 serde_json::from_str("null")?
793 } else {
794 serde_json::from_slice::<Out>(&response_body)?
795 };
796 Ok((link, crate::Response::new(status, headers, parsed_response)))
797 } else {
798 let error = if response_body.is_empty() {
799 ClientError::HttpError {
800 status,
801 headers,
802 error: "empty response".into(),
803 }
804 } else {
805 ClientError::HttpError {
806 status,
807 headers,
808 error: String::from_utf8_lossy(&response_body).into(),
809 }
810 };
811 Err(error)
812 }
813 }
814
815 #[allow(dead_code)]
817 async fn post_form<Out>(
818 &self,
819 uri: &str,
820 form: reqwest::multipart::Form,
821 ) -> ClientResult<crate::Response<Out>>
822 where
823 Out: serde::de::DeserializeOwned + 'static + Send,
824 {
825 let (url, auth) = self.url_and_auth(uri).await?;
826
827 let instance = <&Client>::clone(&self);
828
829 let mut req = instance.client.request(http::Method::POST, url);
830
831 req = req.header(
833 reqwest::header::ACCEPT,
834 reqwest::header::HeaderValue::from_static("application/json"),
835 );
836
837 if let Some(auth_str) = auth {
838 req = req.header(http::header::AUTHORIZATION, &*auth_str);
839 }
840
841 req = req.multipart(form);
842
843 let response = req.send().await?;
844
845 let status = response.status();
846 let headers = response.headers().clone();
847
848 let response_body = response.bytes().await?;
849
850 if status.is_success() {
851 log::debug!("Received successful response. Read payload.");
852 let parsed_response = if status == http::StatusCode::NO_CONTENT
853 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
854 {
855 serde_json::from_str("null")?
856 } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
857 let s = String::from_utf8(response_body.to_vec())?;
859 serde_json::from_value(serde_json::json!(&s))?
860 } else {
861 serde_json::from_slice::<Out>(&response_body)?
862 };
863 Ok(crate::Response::new(status, headers, parsed_response))
864 } else {
865 let error = if response_body.is_empty() {
866 ClientError::HttpError {
867 status,
868 headers,
869 error: "empty response".into(),
870 }
871 } else {
872 ClientError::HttpError {
873 status,
874 headers,
875 error: String::from_utf8_lossy(&response_body).into(),
876 }
877 };
878
879 Err(error)
880 }
881 }
882
883 #[allow(dead_code)]
885 async fn request_with_accept_mime<Out>(
886 &self,
887 method: reqwest::Method,
888 uri: &str,
889 accept_mime_type: &str,
890 ) -> ClientResult<crate::Response<Out>>
891 where
892 Out: serde::de::DeserializeOwned + 'static + Send,
893 {
894 let (url, auth) = self.url_and_auth(uri).await?;
895
896 let instance = <&Client>::clone(&self);
897
898 let mut req = instance.client.request(method, url);
899
900 req = req.header(
902 reqwest::header::ACCEPT,
903 reqwest::header::HeaderValue::from_str(accept_mime_type)?,
904 );
905
906 if let Some(auth_str) = auth {
907 req = req.header(http::header::AUTHORIZATION, &*auth_str);
908 }
909
910 let response = req.send().await?;
911
912 let status = response.status();
913 let headers = response.headers().clone();
914
915 let response_body = response.bytes().await?;
916
917 if status.is_success() {
918 log::debug!("Received successful response. Read payload.");
919 let parsed_response = if status == http::StatusCode::NO_CONTENT
920 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
921 {
922 serde_json::from_str("null")?
923 } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
924 let s = String::from_utf8(response_body.to_vec())?;
926 serde_json::from_value(serde_json::json!(&s))?
927 } else {
928 serde_json::from_slice::<Out>(&response_body)?
929 };
930 Ok(crate::Response::new(status, headers, parsed_response))
931 } else {
932 let error = if response_body.is_empty() {
933 ClientError::HttpError {
934 status,
935 headers,
936 error: "empty response".into(),
937 }
938 } else {
939 ClientError::HttpError {
940 status,
941 headers,
942 error: String::from_utf8_lossy(&response_body).into(),
943 }
944 };
945
946 Err(error)
947 }
948 }
949
950 #[allow(dead_code)]
952 async fn request_with_mime<Out>(
953 &self,
954 method: reqwest::Method,
955 uri: &str,
956 content: &[u8],
957 mime_type: &str,
958 ) -> ClientResult<crate::Response<Out>>
959 where
960 Out: serde::de::DeserializeOwned + 'static + Send,
961 {
962 let (url, auth) = self.url_and_auth(uri).await?;
963
964 let instance = <&Client>::clone(&self);
965
966 let mut req = instance.client.request(method, url);
967
968 req = req.header(
970 reqwest::header::ACCEPT,
971 reqwest::header::HeaderValue::from_static("application/json"),
972 );
973 req = req.header(
974 reqwest::header::CONTENT_TYPE,
975 reqwest::header::HeaderValue::from_bytes(mime_type.as_bytes()).unwrap(),
976 );
977 req = req.header(
979 reqwest::header::HeaderName::from_static("x-upload-content-type"),
980 reqwest::header::HeaderValue::from_static("application/octet-stream"),
981 );
982 req = req.header(
983 reqwest::header::HeaderName::from_static("x-upload-content-length"),
984 reqwest::header::HeaderValue::from_bytes(format!("{}", content.len()).as_bytes())
985 .unwrap(),
986 );
987
988 if let Some(auth_str) = auth {
989 req = req.header(http::header::AUTHORIZATION, &*auth_str);
990 }
991
992 if content.len() > 1 {
993 let b = bytes::Bytes::copy_from_slice(content);
994 req = req.body(b);
996 }
997
998 let response = req.send().await?;
999
1000 let status = response.status();
1001 let headers = response.headers().clone();
1002
1003 let response_body = response.bytes().await?;
1004
1005 if status.is_success() {
1006 log::debug!("Received successful response. Read payload.");
1007 let parsed_response = if status == http::StatusCode::NO_CONTENT
1008 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
1009 {
1010 serde_json::from_str("null")?
1011 } else {
1012 serde_json::from_slice::<Out>(&response_body)?
1013 };
1014 Ok(crate::Response::new(status, headers, parsed_response))
1015 } else {
1016 let error = if response_body.is_empty() {
1017 ClientError::HttpError {
1018 status,
1019 headers,
1020 error: "empty response".into(),
1021 }
1022 } else {
1023 ClientError::HttpError {
1024 status,
1025 headers,
1026 error: String::from_utf8_lossy(&response_body).into(),
1027 }
1028 };
1029
1030 Err(error)
1031 }
1032 }
1033
1034 async fn request_entity<D>(
1035 &self,
1036 method: http::Method,
1037 uri: &str,
1038 message: Message,
1039 ) -> ClientResult<crate::Response<D>>
1040 where
1041 D: serde::de::DeserializeOwned + 'static + Send,
1042 {
1043 let r = self.request(method, uri, message).await?;
1044 Ok(r)
1045 }
1046
1047 #[allow(dead_code)]
1048 async fn get<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1049 where
1050 D: serde::de::DeserializeOwned + 'static + Send,
1051 {
1052 self.request_entity(http::Method::GET, uri, message).await
1053 }
1054
1055 #[allow(dead_code)]
1056 async fn get_all_pages<D>(&self, uri: &str, _message: Message) -> ClientResult<Response<Vec<D>>>
1057 where
1058 D: serde::de::DeserializeOwned + 'static + Send,
1059 {
1060 self.unfold(uri).await
1062 }
1063
1064 #[allow(dead_code)]
1066 async fn unfold<D>(&self, uri: &str) -> ClientResult<crate::Response<Vec<D>>>
1067 where
1068 D: serde::de::DeserializeOwned + 'static + Send,
1069 {
1070 let mut global_items = Vec::new();
1071 let (new_link, mut response) = self.get_pages(uri).await?;
1072 let mut link = new_link;
1073 while !response.body.is_empty() {
1074 global_items.append(&mut response.body);
1075 if let Some(url) = &link {
1077 let url = reqwest::Url::parse(&url.0)?;
1078 let (new_link, new_response) = self.get_pages_url(&url).await?;
1079 link = new_link;
1080 response = new_response;
1081 }
1082 }
1083
1084 Ok(Response::new(
1085 response.status,
1086 response.headers,
1087 global_items,
1088 ))
1089 }
1090
1091 #[allow(dead_code)]
1092 async fn get_pages<D>(
1093 &self,
1094 uri: &str,
1095 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
1096 where
1097 D: serde::de::DeserializeOwned + 'static + Send,
1098 {
1099 self.request_with_links(http::Method::GET, uri, Message::default())
1100 .await
1101 }
1102
1103 #[allow(dead_code)]
1104 async fn get_pages_url<D>(
1105 &self,
1106 url: &reqwest::Url,
1107 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
1108 where
1109 D: serde::de::DeserializeOwned + 'static + Send,
1110 {
1111 self.request_with_links(http::Method::GET, url.as_str(), Message::default())
1112 .await
1113 }
1114
1115 #[allow(dead_code)]
1116 async fn post<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1117 where
1118 D: serde::de::DeserializeOwned + 'static + Send,
1119 {
1120 self.request_entity(http::Method::POST, uri, message).await
1121 }
1122
1123 #[allow(dead_code)]
1124 async fn patch<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1125 where
1126 D: serde::de::DeserializeOwned + 'static + Send,
1127 {
1128 self.request_entity(http::Method::PATCH, uri, message).await
1129 }
1130
1131 #[allow(dead_code)]
1132 async fn put<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1133 where
1134 D: serde::de::DeserializeOwned + 'static + Send,
1135 {
1136 self.request_entity(http::Method::PUT, uri, message).await
1137 }
1138
1139 #[allow(dead_code)]
1140 async fn delete<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1141 where
1142 D: serde::de::DeserializeOwned + 'static + Send,
1143 {
1144 self.request_entity(http::Method::DELETE, uri, message)
1145 .await
1146 }
1147
1148 pub fn asps(&self) -> asps::Asps {
1150 asps::Asps::new(self.clone())
1151 }
1152
1153 pub fn channels(&self) -> channels::Channels {
1155 channels::Channels::new(self.clone())
1156 }
1157
1158 pub fn chromeosdevices(&self) -> chromeosdevices::Chromeosdevices {
1160 chromeosdevices::Chromeosdevices::new(self.clone())
1161 }
1162
1163 pub fn customer(&self) -> customer::Customer {
1165 customer::Customer::new(self.clone())
1166 }
1167
1168 pub fn customers(&self) -> customers::Customers {
1170 customers::Customers::new(self.clone())
1171 }
1172
1173 pub fn domain_aliases(&self) -> domain_aliases::DomainAliases {
1175 domain_aliases::DomainAliases::new(self.clone())
1176 }
1177
1178 pub fn domains(&self) -> domains::Domains {
1180 domains::Domains::new(self.clone())
1181 }
1182
1183 pub fn groups(&self) -> groups::Groups {
1185 groups::Groups::new(self.clone())
1186 }
1187
1188 pub fn members(&self) -> members::Members {
1190 members::Members::new(self.clone())
1191 }
1192
1193 pub fn mobiledevices(&self) -> mobiledevices::Mobiledevices {
1195 mobiledevices::Mobiledevices::new(self.clone())
1196 }
1197
1198 pub fn orgunits(&self) -> orgunits::Orgunits {
1200 orgunits::Orgunits::new(self.clone())
1201 }
1202
1203 pub fn privileges(&self) -> privileges::Privileges {
1205 privileges::Privileges::new(self.clone())
1206 }
1207
1208 pub fn resources(&self) -> resources::Resources {
1210 resources::Resources::new(self.clone())
1211 }
1212
1213 pub fn role_assignments(&self) -> role_assignments::RoleAssignments {
1215 role_assignments::RoleAssignments::new(self.clone())
1216 }
1217
1218 pub fn roles(&self) -> roles::Roles {
1220 roles::Roles::new(self.clone())
1221 }
1222
1223 pub fn schemas(&self) -> schemas::Schemas {
1225 schemas::Schemas::new(self.clone())
1226 }
1227
1228 pub fn tokens(&self) -> tokens::Tokens {
1230 tokens::Tokens::new(self.clone())
1231 }
1232
1233 pub fn two_step_verification(&self) -> two_step_verification::TwoStepVerification {
1235 two_step_verification::TwoStepVerification::new(self.clone())
1236 }
1237
1238 pub fn users(&self) -> users::Users {
1240 users::Users::new(self.clone())
1241 }
1242
1243 pub fn verification_codes(&self) -> verification_codes::VerificationCodes {
1245 verification_codes::VerificationCodes::new(self.clone())
1246 }
1247}