-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix(errors): include retry-after in api errors #802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
a8adf59
ba21290
fefb4e7
228d250
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -462,6 +462,11 @@ pub async fn execute_method( | |
| .and_then(|v| v.to_str().ok()) | ||
| .unwrap_or("") | ||
| .to_string(); | ||
| let retry_after = response | ||
| .headers() | ||
| .get(reqwest::header::RETRY_AFTER) | ||
| .and_then(|v| v.to_str().ok()) | ||
| .map(str::to_string); | ||
|
|
||
| if !status.is_success() { | ||
| let error_body = response.text().await.unwrap_or_default(); | ||
|
|
@@ -472,7 +477,7 @@ pub async fn execute_method( | |
| latency_ms = latency_ms, | ||
| "API error" | ||
| ); | ||
| return handle_error_response(status, &error_body, &auth_method); | ||
| return handle_error_response(status, &error_body, &auth_method, retry_after); | ||
| } | ||
|
|
||
| tracing::debug!( | ||
|
|
@@ -754,6 +759,7 @@ fn handle_error_response<T>( | |
| status: reqwest::StatusCode, | ||
| error_body: &str, | ||
| auth_method: &AuthMethod, | ||
| retry_after: Option<String>, | ||
| ) -> Result<T, GwsError> { | ||
| // If 401/403 and no auth was provided, give a helpful message | ||
| if (status.as_u16() == 401 || status.as_u16() == 403) && *auth_method == AuthMethod::None { | ||
|
|
@@ -800,6 +806,7 @@ fn handle_error_response<T>( | |
| message, | ||
| reason, | ||
| enable_url, | ||
| retry_after, | ||
| }); | ||
| } | ||
| } | ||
|
|
@@ -809,6 +816,7 @@ fn handle_error_response<T>( | |
| message: error_body.to_string(), | ||
| reason: "httpError".to_string(), | ||
| enable_url: None, | ||
| retry_after, | ||
| }) | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
|
|
@@ -1947,6 +1955,7 @@ mod tests { | |
| reqwest::StatusCode::UNAUTHORIZED, | ||
| "Unauthorized", | ||
| &AuthMethod::None, | ||
| None, | ||
| ) | ||
| .unwrap_err(); | ||
| match err { | ||
|
|
@@ -1973,6 +1982,7 @@ mod tests { | |
| reqwest::StatusCode::UNAUTHORIZED, | ||
| &json_err, | ||
| &AuthMethod::OAuth, | ||
| None, | ||
| ) | ||
| .unwrap_err(); | ||
| match err { | ||
|
|
@@ -2008,6 +2018,7 @@ mod tests { | |
| reqwest::StatusCode::BAD_REQUEST, | ||
| &json_err, | ||
| &AuthMethod::OAuth, | ||
| None, | ||
| ) | ||
| .unwrap_err(); | ||
| match err { | ||
|
|
@@ -2024,6 +2035,31 @@ mod tests { | |
| _ => panic!("Expected Api error"), | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_handle_error_response_preserves_retry_after_header() { | ||
| let json_err = json!({ | ||
| "error": { | ||
| "code": 429, | ||
| "message": "Quota exceeded", | ||
| "errors": [{ "reason": "rateLimitExceeded" }] | ||
| } | ||
| }) | ||
| .to_string(); | ||
|
|
||
| let err = handle_error_response::<()>( | ||
| reqwest::StatusCode::TOO_MANY_REQUESTS, | ||
| &json_err, | ||
| &AuthMethod::OAuth, | ||
| Some("120".to_string()), | ||
| ) | ||
| .unwrap_err(); | ||
|
|
||
| match err { | ||
| GwsError::Api { retry_after, .. } => assert_eq!(retry_after.as_deref(), Some("120")), | ||
| _ => panic!("Expected Api error"), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[tokio::test] | ||
|
|
@@ -2156,6 +2192,7 @@ fn test_handle_error_response_non_json() { | |
| reqwest::StatusCode::INTERNAL_SERVER_ERROR, | ||
| "Internal Server Error Text", | ||
| &AuthMethod::OAuth, | ||
| None, | ||
| ) | ||
| .unwrap_err(); | ||
| match err { | ||
|
|
@@ -2223,6 +2260,7 @@ fn test_handle_error_response_access_not_configured_with_url() { | |
| reqwest::StatusCode::FORBIDDEN, | ||
| &json_err, | ||
| &AuthMethod::OAuth, | ||
| None, | ||
| ) | ||
| .unwrap_err(); | ||
|
|
||
|
|
@@ -2260,6 +2298,7 @@ fn test_handle_error_response_access_not_configured_errors_array() { | |
| reqwest::StatusCode::FORBIDDEN, | ||
| &json_err, | ||
| &AuthMethod::OAuth, | ||
| None, | ||
| ) | ||
| .unwrap_err(); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -274,6 +274,7 @@ async fn handle_agenda(matches: &ArgMatches) -> Result<(), GwsError> { | |
| message: err, | ||
| reason: "calendarList_failed".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The References
|
||
| }); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -221,6 +221,7 @@ pub(super) async fn handle_subscribe( | |
| message: format!("Failed to create Pub/Sub topic: {body}"), | ||
| reason: "pubsubError".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| }); | ||
| } | ||
|
|
||
|
|
@@ -246,6 +247,7 @@ pub(super) async fn handle_subscribe( | |
| message: format!("Failed to create Pub/Sub subscription: {body}"), | ||
| reason: "pubsubError".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
| }); | ||
| } | ||
|
|
||
|
|
@@ -421,6 +423,7 @@ async fn pull_loop( | |
| message: format!("Pub/Sub pull failed: {body}"), | ||
| reason: "pubsubError".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
| }); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -438,6 +438,7 @@ pub(super) fn build_api_error(status: u16, body: &str, context: &str) -> GwsErro | |
| message: format!("{context}: {message}"), | ||
| reason, | ||
| enable_url, | ||
| retry_after: None, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The References
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in ba21290. |
||
| } | ||
| } | ||
|
|
||
|
|
@@ -3614,6 +3615,7 @@ mod tests { | |
| message, | ||
| reason, | ||
| enable_url, | ||
| .. | ||
| } => { | ||
| assert_eq!(code, 403); | ||
| assert!(message.contains("Test context")); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,6 +65,7 @@ pub async fn handle_triage(matches: &ArgMatches) -> Result<(), GwsError> { | |
| message: err, | ||
| reason: "list_failed".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| }); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -67,6 +67,7 @@ pub(super) async fn handle_watch( | |
| message: format!("Failed to create Pub/Sub topic: {body}"), | ||
| reason: "pubsubError".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| }); | ||
| } | ||
|
|
||
|
|
@@ -132,6 +133,7 @@ pub(super) async fn handle_watch( | |
| message: format!("Failed to create Pub/Sub subscription: {body}"), | ||
| reason: "pubsubError".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
| }); | ||
| } | ||
|
|
||
|
|
@@ -168,6 +170,7 @@ pub(super) async fn handle_watch( | |
| ), | ||
| reason: "gmailError".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
| }); | ||
| } | ||
|
|
||
|
|
@@ -301,6 +304,7 @@ async fn watch_pull_loop( | |
| message: format!("Pub/Sub pull failed: {body}"), | ||
| reason: "pubsubError".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
| }); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -251,6 +251,7 @@ async fn get_json( | |
| message: body, | ||
| reason: "workflow_request_failed".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| }); | ||
| } | ||
|
|
||
|
|
@@ -517,6 +518,7 @@ async fn handle_email_to_task(matches: &ArgMatches) -> Result<(), GwsError> { | |
| message: body, | ||
| reason: "task_create_failed".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
| }); | ||
| } | ||
|
|
||
|
|
@@ -676,6 +678,7 @@ async fn handle_file_announce(matches: &ArgMatches) -> Result<(), GwsError> { | |
| message: body, | ||
| reason: "chat_send_failed".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
| }); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,6 +92,7 @@ async fn fetch_account_timezone(client: &reqwest::Client, token: &str) -> Result | |
| message: body, | ||
| reason: "timezone_fetch_failed".to_string(), | ||
| enable_url: None, | ||
| retry_after: None, | ||
| }); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for extracting the
Retry-Afterheader is duplicated here and incrates/google-workspace-cli/src/helpers/gmail/mod.rs. It should be refactored into a shared helper function to ensure consistency and reduce duplication.