The cross-platform version manager toolset
crates.io/crates/hyper-jump
1use anyhow::anyhow;
2use anyhow::Result;
3use reqwest::Client;
4use serde::de::DeserializeOwned;
5use serde::Deserialize;
6use serde::Serialize;
7
8/// Represents an error response from the GitHub API.
9///
10/// This struct contains information about an error response from the GitHub
11/// API, including the error message and the URL of the documentation related to
12/// the error.
13///
14/// # Fields
15///
16/// * `message: String` - The error message from the GitHub API.
17/// * `documentation_url: String` - The URL of the documentation related to the
18/// error.
19///
20/// # Example
21///
22/// ```rust
23/// let error_response = ErrorResponse {
24/// message: "Not Found".to_string(),
25/// documentation_url: "https://docs.github.com/rest".to_string(),
26/// };
27/// println!("The error message is {}", error_response.message);
28/// println!(
29/// "The documentation URL is {}",
30/// error_response.documentation_url
31/// );
32/// ```
33#[derive(Debug, Deserialize, Serialize)]
34pub struct ErrorResponse {
35 pub message: String,
36 pub documentation_url: String,
37}
38
39pub async fn api(client: Option<&Client>, url: String) -> Result<String> {
40 let response = client
41 .expect("Client not found")
42 .get(url)
43 .header(reqwest::header::USER_AGENT, "hyper-jump")
44 .header(reqwest::header::ACCEPT, "application/vnd.github.v3+json")
45 .send()
46 .await?
47 .error_for_status()?
48 .text()
49 .await?;
50
51 Ok(response)
52}
53
54/// Deserializes a JSON response from the GitHub API.
55///
56/// # Parameters
57///
58/// * `response: String` - The JSON response from the GitHub API as a string.
59///
60/// # Returns
61///
62/// * `Result<T>` - The deserialized response as the specified type `T`, or an
63/// error if the response could not be deserialized or contains an error
64/// message.
65///
66/// # Errors
67///
68/// This function will return an error if the response contains a "message"
69/// field (indicating an error from the GitHub API), or if the response could
70/// not be deserialized into the specified type `T`.
71///
72/// # Example
73///
74/// ```rust
75/// let response = "{\"data\": \"some data\"}";
76/// let result: Result<MyType> = deserialize_response(response);
77/// match result {
78/// Ok(data) => println!("Received data: {:?}", data),
79/// Err(e) => println!("An error occurred: {:?}", e),
80/// }
81/// ```
82pub fn deserialize_response<T: DeserializeOwned>(response: String) -> Result<T> {
83 let value: serde_json::Value = serde_json::from_str(&response)?;
84 if value.get("message").is_some() {
85 let result: ErrorResponse = serde_json::from_value(value)?;
86 if result.documentation_url.contains("rate-limiting") {
87 return Err(anyhow!("Rate limited by GitHub API"));
88 }
89
90 return Err(anyhow!(result.message));
91 }
92
93 Ok(serde_json::from_value(value)?)
94}