Skip to content

Commit fe383dd

Browse files
authored
fix(errors): pass through client error status codes (#77)
## What I'm changing I noticed that when an ApiClientError is thrown (e.g. the source API returns a `401` for a private repository), the proxy throws a `502` gateway error. This obfuscates the underlying error. Instead, we should pass that error through from the proxy. <details> <summary>Running into this error</summary> I have a disabled repo at https://source.coop/alukach/test-repo. The API returns a `401` when I attempt to access it: https://source.coop/api/v1/repositories/alukach/test-repo However, the data proxy currently returns a `502` because the `401`: ```sh ▶ curl https://data.source.coop/alukach/test-repo/xyz --verbose // ... < HTTP/2 502 < date: Thu, 29 May 2025 19:42:09 GMT < content-length: 203 < x-version: 0.1.28 < access-control-allow-credentials: true < vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers < * Connection #0 to host data.source.coop left intact Internal Server Error: api threw a client error (url https://source.coop/api/v1/repositories/alukach/test-repo, status 401, message {"code":401,"message":"You are not authorized to perform this action"})% ``` </details> ## How I did it Updated the ResponseError implementation for BackendError to correctly pass through client error status codes from ApiClientError, ensuring that the appropriate status code is returned in the response. <!-- Discuss the implementation strategy and considerations made --> ## How to test it ## PR Checklist - [x] This PR has **no** breaking changes. - [x] I have updated or added new tests to cover the changes in this PR. - [ ] This PR affects the [Source Cooperative Frontend & API](https://github.com/source-cooperative/source.coop), and I have opened issue/PR #XXX to track the change. ## Related Issues <!-- Reference any existing related GitHub Issues -->
1 parent 496373c commit fe383dd

File tree

1 file changed

+26
-4
lines changed

1 file changed

+26
-4
lines changed

src/utils/errors.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ impl error::ResponseError for BackendError {
9898

9999
fn status_code(&self) -> StatusCode {
100100
match self {
101+
// Pass through client error status codes
102+
BackendError::ApiClientError { status, .. } => {
103+
StatusCode::from_u16(*status).unwrap_or(StatusCode::BAD_REQUEST)
104+
}
105+
101106
// 400
102107
BackendError::InvalidRequest(_)
103108
| BackendError::UnsupportedAuthMethod(_)
@@ -114,7 +119,6 @@ impl error::ResponseError for BackendError {
114119
// 502
115120
BackendError::ReqwestError(_)
116121
| BackendError::ApiServerError { .. }
117-
| BackendError::ApiClientError { .. }
118122
| BackendError::RepositoryPermissionsNotFound
119123
| BackendError::AzureError(_)
120124
| BackendError::S3Error(_) => StatusCode::BAD_GATEWAY,
@@ -508,16 +512,34 @@ mod tests {
508512
}
509513

510514
#[test]
511-
fn should_handle_api_client_error() {
515+
fn should_handle_api_client_error_400() {
512516
let error = BackendError::ApiClientError {
513517
url: "https://api.example.com".to_string(),
514518
status: 400,
515519
message: "Bad Request".to_string(),
516520
};
517521
assert_eq!(
518522
error.status_code(),
519-
StatusCode::BAD_GATEWAY,
520-
"expected status code to be 502"
523+
StatusCode::BAD_REQUEST,
524+
"expected status code to be 400"
525+
);
526+
assert!(
527+
error.to_string().contains("api threw a client error"),
528+
"expected error message to mention client error"
529+
);
530+
}
531+
532+
#[test]
533+
fn should_handle_api_client_error_404() {
534+
let error = BackendError::ApiClientError {
535+
url: "https://api.example.com".to_string(),
536+
status: 404,
537+
message: "Bad Request".to_string(),
538+
};
539+
assert_eq!(
540+
error.status_code(),
541+
StatusCode::NOT_FOUND,
542+
"expected status code to be 404"
521543
);
522544
assert!(
523545
error.to_string().contains("api threw a client error"),

0 commit comments

Comments
 (0)