Skip to main content

google_search_console_api/
lib.rs

1//! # Google Search Console API Client
2//!
3//! An unofficial Rust client library for the Google Search Console API.
4//!
5//! ## Features
6//!
7//! - **Search Analytics** - Query search performance data
8//! - **Sitemaps** - Manage sitemaps
9//! - **Sites** - Manage sites
10//! - **URL Inspection** - Inspect URLs for indexing status
11//! - **Mobile Friendly Test** - Test mobile friendliness
12//!
13//! ## Example
14//!
15//! ```rust,no_run
16//! use google_search_console_api::SearchConsoleApi;
17//! use google_search_console_api::search_analytics::query::SearchAnalyticsQueryRequest;
18//! use google_search_console_api::types::Dimension;
19//!
20//! #[tokio::main]
21//! async fn main() {
22//!     let token = "your_oauth_token";
23//!     let site_url = "https://example.com/";
24//!
25//!     let request = SearchAnalyticsQueryRequest::builder("2024-01-01", "2024-01-31")
26//!         .dimensions(vec![Dimension::Query, Dimension::Page])
27//!         .row_limit(100)
28//!         .build();
29//!
30//!     let response = SearchConsoleApi::search_analytics()
31//!         .query(token, site_url, request)
32//!         .await;
33//! }
34//! ```
35
36mod error;
37mod http;
38
39pub mod mobile_friendly_test;
40pub mod search_analytics;
41pub mod sitemaps;
42pub mod sites;
43pub mod types;
44pub mod url_inspection;
45
46use serde::{Deserialize, Serialize};
47use serde_json::{json, Value};
48use urlencoding::encode;
49
50pub use error::*;
51
52use crate::http::HttpClient;
53use crate::mobile_friendly_test::{RequestMobileFriendlyTest, ResponseMobileFriendlyTest};
54use crate::search_analytics::query::{SearchAnalyticsQueryRequest, SearchAnalyticsQueryResponse};
55use crate::sitemaps::ResponseSitemapApiList;
56use crate::sites::{ResponseSiteApi, ResponseSiteListApi};
57use crate::url_inspection::{RequestUrlInspection, ResponseInspectionResult};
58
59/// Main entry point for the Google Search Console API.
60///
61/// Provides access to all API endpoints through method chaining.
62///
63/// # Example
64///
65/// ```rust,no_run
66/// use google_search_console_api::SearchConsoleApi;
67///
68/// # async fn example() {
69/// let sites = SearchConsoleApi::sites().list("token").await;
70/// # }
71/// ```
72pub struct SearchConsoleApi;
73
74impl SearchConsoleApi {
75    /// Access the Search Analytics API.
76    ///
77    /// Query search performance data including clicks, impressions, CTR, and position.
78    pub fn search_analytics() -> SearchAnalyticsApi {
79        SearchAnalyticsApi
80    }
81
82    /// Access the Sitemaps API.
83    ///
84    /// List, submit, and delete sitemaps for your sites.
85    pub fn sitemaps() -> SitemapsApi {
86        SitemapsApi
87    }
88
89    /// Access the Sites API.
90    ///
91    /// Add, remove, and list sites in your Search Console account.
92    pub fn sites() -> SitesApi {
93        SitesApi
94    }
95
96    /// Access the URL Inspection API.
97    ///
98    /// Inspect URLs for indexing status, crawl info, and more.
99    pub fn url_inspection() -> UrlInspectionApi {
100        UrlInspectionApi
101    }
102
103    /// Access the Mobile Friendly Test API.
104    ///
105    /// Test whether a page is mobile-friendly.
106    pub fn mobile_friendly_test() -> MobileFriendlyTestApi {
107        MobileFriendlyTestApi
108    }
109}
110
111/// Search Analytics API client.
112///
113/// Query search traffic data for your site.
114///
115/// # API Reference
116///
117/// <https://developers.google.com/webmaster-tools/v1/searchanalytics>
118#[derive(Default)]
119pub struct SearchAnalyticsApi;
120
121impl SearchAnalyticsApi {
122    /// Query search analytics data.
123    ///
124    /// # Arguments
125    ///
126    /// * `token` - OAuth2 access token
127    /// * `url` - Site URL (e.g., `https://example.com/`)
128    /// * `request` - Query parameters
129    ///
130    /// # Example
131    ///
132    /// ```rust,no_run
133    /// use google_search_console_api::SearchConsoleApi;
134    /// use google_search_console_api::search_analytics::query::SearchAnalyticsQueryRequest;
135    ///
136    /// # async fn example() {
137    /// let request = SearchAnalyticsQueryRequest::builder("2024-01-01", "2024-01-31")
138    ///     .row_limit(100)
139    ///     .build();
140    ///
141    /// let response = SearchConsoleApi::search_analytics()
142    ///     .query("token", "https://example.com/", request)
143    ///     .await;
144    /// # }
145    /// ```
146    pub async fn query(
147        &self,
148        token: &str,
149        url: &str,
150        request: SearchAnalyticsQueryRequest,
151    ) -> Result<SearchAnalyticsQueryResponse, GoogleApiError> {
152        HttpClient::post(
153            token,
154            &format!(
155                "https://www.googleapis.com/webmasters/v3/sites/{}/searchAnalytics/query",
156                encode(url)
157            ),
158            request,
159        )
160        .await
161    }
162}
163
164#[derive(Default, Debug, Serialize, Deserialize, Clone)]
165pub(crate) struct DummyRequest {}
166
167/// Sitemaps API client.
168///
169/// Manage sitemaps for your sites.
170///
171/// # API Reference
172///
173/// <https://developers.google.com/webmaster-tools/v1/sitemaps>
174#[derive(Default)]
175pub struct SitemapsApi;
176
177impl SitemapsApi {
178    /// Delete a sitemap.
179    ///
180    /// # Arguments
181    ///
182    /// * `token` - OAuth2 access token
183    /// * `site_url` - Site URL
184    /// * `feed_path` - Full URL of the sitemap to delete
185    pub async fn delete(
186        &self,
187        token: &str,
188        site_url: &str,
189        feed_path: &str,
190    ) -> Result<Value, GoogleApiError> {
191        HttpClient::delete(
192            token,
193            &format!(
194                "https://www.googleapis.com/webmasters/v3/sites/{}/sitemaps/{}",
195                encode(site_url),
196                encode(feed_path)
197            ),
198            json!({}),
199        )
200        .await
201    }
202
203    /// Get information about a specific sitemap.
204    ///
205    /// # Arguments
206    ///
207    /// * `token` - OAuth2 access token
208    /// * `site_url` - Site URL
209    /// * `feed` - Full URL of the sitemap
210    pub async fn get(
211        &self,
212        token: &str,
213        site_url: &str,
214        feed: &str,
215    ) -> Result<Value, GoogleApiError> {
216        HttpClient::get(
217            token,
218            &format!(
219                "https://www.googleapis.com/webmasters/v3/sites/{}/sitemaps/{}",
220                encode(site_url),
221                encode(feed)
222            ),
223            json!({}),
224        )
225        .await
226    }
227
228    /// List all sitemaps for a site.
229    ///
230    /// # Arguments
231    ///
232    /// * `token` - OAuth2 access token
233    /// * `site_url` - Site URL
234    pub async fn list(
235        &self,
236        token: &str,
237        site_url: &str,
238    ) -> Result<ResponseSitemapApiList, GoogleApiError> {
239        HttpClient::get(
240            token,
241            &format!(
242                "https://www.googleapis.com/webmasters/v3/sites/{}/sitemaps",
243                encode(site_url)
244            ),
245            DummyRequest::default(),
246        )
247        .await
248    }
249
250    /// Resubmit a sitemap.
251    ///
252    /// # Arguments
253    ///
254    /// * `token` - OAuth2 access token
255    /// * `site_url` - Site URL
256    /// * `feed` - Full URL of the sitemap
257    pub async fn put(
258        &self,
259        token: &str,
260        site_url: &str,
261        feed: &str,
262    ) -> Result<Value, GoogleApiError> {
263        HttpClient::post(
264            token,
265            &format!(
266                "https://www.googleapis.com/webmasters/v3/sites/{}/sitemaps/{}",
267                encode(site_url),
268                encode(feed)
269            ),
270            json!({}),
271        )
272        .await
273    }
274
275    /// Submit a new sitemap.
276    ///
277    /// # Arguments
278    ///
279    /// * `token` - OAuth2 access token
280    /// * `site_url` - Site URL
281    /// * `feed` - Full URL of the sitemap to submit
282    pub async fn submit(
283        &self,
284        token: &str,
285        site_url: &str,
286        feed: &str,
287    ) -> Result<Value, GoogleApiError> {
288        HttpClient::put(
289            token,
290            &format!(
291                "https://www.googleapis.com/webmasters/v3/sites/{}/sitemaps/{}",
292                encode(site_url),
293                encode(feed)
294            ),
295            json!({}),
296        )
297        .await
298    }
299}
300
301/// Sites API client.
302///
303/// Manage sites in your Search Console account.
304///
305/// # API Reference
306///
307/// <https://developers.google.com/webmaster-tools/v1/sites>
308#[derive(Default)]
309pub struct SitesApi;
310
311impl SitesApi {
312    /// Add a site to Search Console.
313    ///
314    /// # Arguments
315    ///
316    /// * `token` - OAuth2 access token
317    /// * `site_url` - URL of the site to add
318    pub async fn add(&self, token: &str, site_url: &str) -> Result<Value, GoogleApiError> {
319        HttpClient::put(
320            token,
321            &format!(
322                "https://www.googleapis.com/webmasters/v3/sites/{}",
323                encode(site_url)
324            ),
325            DummyRequest::default(),
326        )
327        .await
328    }
329
330    /// Remove a site from Search Console.
331    ///
332    /// # Arguments
333    ///
334    /// * `token` - OAuth2 access token
335    /// * `site_url` - URL of the site to remove
336    pub async fn delete(&self, token: &str, site_url: &str) -> Result<Value, GoogleApiError> {
337        HttpClient::delete(
338            token,
339            &format!(
340                "https://www.googleapis.com/webmasters/v3/sites/{}",
341                encode(site_url)
342            ),
343            DummyRequest::default(),
344        )
345        .await
346    }
347
348    /// Get information about a specific site.
349    ///
350    /// # Arguments
351    ///
352    /// * `token` - OAuth2 access token
353    /// * `site_url` - URL of the site
354    pub async fn get(
355        &self,
356        token: &str,
357        site_url: &str,
358    ) -> Result<ResponseSiteApi, GoogleApiError> {
359        HttpClient::get(
360            token,
361            &format!(
362                "https://www.googleapis.com/webmasters/v3/sites/{}",
363                encode(site_url)
364            ),
365            DummyRequest::default(),
366        )
367        .await
368    }
369
370    /// List all sites in your Search Console account.
371    ///
372    /// # Arguments
373    ///
374    /// * `token` - OAuth2 access token
375    pub async fn list(&self, token: &str) -> Result<ResponseSiteListApi, GoogleApiError> {
376        HttpClient::get(
377            token,
378            "https://www.googleapis.com/webmasters/v3/sites",
379            DummyRequest::default(),
380        )
381        .await
382    }
383}
384
385/// URL Inspection API client.
386///
387/// Inspect URLs for indexing status and other information.
388///
389/// # API Reference
390///
391/// <https://developers.google.com/webmaster-tools/v1/urlInspection.index>
392#[derive(Default)]
393pub struct UrlInspectionApi;
394
395impl UrlInspectionApi {
396    /// Inspect a URL.
397    ///
398    /// Returns indexing status, crawl info, AMP status, mobile usability, and rich results.
399    ///
400    /// # Arguments
401    ///
402    /// * `token` - OAuth2 access token
403    /// * `request` - Inspection request parameters
404    pub async fn inspect(
405        &self,
406        token: &str,
407        request: &RequestUrlInspection,
408    ) -> Result<ResponseInspectionResult, GoogleApiError> {
409        HttpClient::post(
410            token,
411            "https://searchconsole.googleapis.com/v1/urlInspection/index:inspect",
412            request,
413        )
414        .await
415    }
416}
417
418/// Mobile Friendly Test API client.
419///
420/// Test whether a page is mobile-friendly.
421///
422/// # API Reference
423///
424/// <https://developers.google.com/webmaster-tools/v1/urlTestingTools.mobileFriendlyTest>
425#[derive(Default)]
426pub struct MobileFriendlyTestApi;
427
428impl MobileFriendlyTestApi {
429    /// Run a mobile-friendly test.
430    ///
431    /// Note: This API uses an API key instead of OAuth2.
432    ///
433    /// # Arguments
434    ///
435    /// * `api_key` - Google API key
436    /// * `request` - Test request parameters
437    pub async fn run(
438        &self,
439        api_key: &str,
440        request: &RequestMobileFriendlyTest,
441    ) -> Result<ResponseMobileFriendlyTest, GoogleApiError> {
442        HttpClient::post(
443            "",
444            &format!(
445                "https://searchconsole.googleapis.com/v1/urlTestingTools/mobileFriendlyTest:run?key={}",
446                api_key
447            ),
448            request,
449        )
450        .await
451    }
452}