firebase_admin_sdk/crashlytics/mod.rs
1//! Firebase Crashlytics module.
2//!
3//! This module provides functionality for managing Crashlytics data.
4//! Currently, it supports deleting crash reports for a specific user, which is useful for
5//! privacy compliance (e.g., "Right to be Forgotten").
6//!
7//! # Examples
8//!
9//! ```rust,no_run
10//! # use firebase_admin_sdk::FirebaseApp;
11//! # async fn run(app: FirebaseApp) {
12//! let crashlytics = app.crashlytics();
13//!
14//! // Delete crash reports for a user
15//! let _ = crashlytics.delete_crash_reports("your-app-id", "user-uid").await;
16//! # }
17//! ```
18
19use crate::core::middleware::AuthMiddleware;
20use reqwest::Client;
21use reqwest::StatusCode;
22use reqwest_middleware::ClientBuilder;
23use reqwest_middleware::ClientWithMiddleware;
24use reqwest_retry::policies::ExponentialBackoff;
25use reqwest_retry::RetryTransientMiddleware;
26use thiserror::Error;
27
28/// Error type for Firebase Crashlytics operations.
29#[derive(Debug, Error)]
30pub enum Error {
31 /// An error occurred while sending the request or receiving the response.
32 #[error("Request error: {0}")]
33 Reqwest(#[from] reqwest::Error),
34 /// The middleware encountered an error (e.g., authentication failed).
35 #[error("Middleware error: {0}")]
36 Middleware(#[from] reqwest_middleware::Error),
37 /// The API returned an error status code.
38 #[error("API error: {0}")]
39 Api(StatusCode),
40}
41
42const CRASHLYTICS_V1_API: &str =
43 "https://firebasecrashlytics.googleapis.com/v1alpha/projects/{project_id}";
44
45/// Client for interacting with the Firebase Crashlytics API.
46pub struct FirebaseCrashlytics {
47 client: ClientWithMiddleware,
48 base_url: String,
49}
50
51impl FirebaseCrashlytics {
52 /// Creates a new `FirebaseCrashlytics` client.
53 pub fn new(middleware: AuthMiddleware) -> Self {
54 let retry_policy = ExponentialBackoff::builder().build_with_max_retries(3);
55
56 let client = ClientBuilder::new(Client::new())
57 .with(RetryTransientMiddleware::new_with_policy(retry_policy))
58 .with(middleware.clone())
59 .build();
60
61 let project_id = middleware
62 .key
63 .project_id
64 .clone()
65 .unwrap_or_default();
66
67 let base_url = CRASHLYTICS_V1_API.replace("{project_id}", &project_id);
68
69 Self { client, base_url }
70 }
71
72 /// Creates a new `FirebaseCrashlytics` client with a custom client and base URL.
73 /// Internal use only, primarily for testing.
74 #[allow(dead_code)]
75 pub(crate) fn new_with_client(client: ClientWithMiddleware, base_url: String) -> Self {
76 Self { client, base_url }
77 }
78
79 /// Enqueues a request to permanently remove crash reports associated with the specified user.
80 ///
81 /// # Arguments
82 ///
83 /// * `app_id` - The App ID (e.g., the Google App ID, like `1:1234567890:android:321abc456def7890`).
84 /// * `user_id` - The unique identifier of the user whose crash reports should be deleted.
85 ///
86 /// # Errors
87 ///
88 /// Returns an error if the request fails or if the API returns a non-success status code.
89 pub async fn delete_crash_reports(&self, app_id: &str, user_id: &str) -> Result<(), Error> {
90 // The resource name format is: projects/{project}/apps/{app}/users/{user}/crashReports
91 let url = format!(
92 "{}/apps/{}/users/{}/crashReports",
93 self.base_url, app_id, user_id
94 );
95
96 let response = self.client.delete(&url).send().await?;
97
98 if response.status().is_success() {
99 Ok(())
100 } else {
101 Err(Error::Api(response.status()))
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests;