Skip to content

Commit

Permalink
fix(api): ensure that endpoint path is versioned
Browse files Browse the repository at this point in the history
Bitly API deprecated endpoint paths without specific API version (e.g.,
`https://api-ssl.bitly.com/shorten`). By mistake, the API client used to
make such requests and got 410 (GONE) responses back.

This commit fixes this issue by correctly constructing an API endpoint
URL which includes the API version (e.g,
`https://api-ssl.bitly.com/v4/shorten`).
  • Loading branch information
matyama committed Aug 19, 2024
1 parent 03906d0 commit 0ffff1e
Showing 1 changed file with 33 additions and 10 deletions.
43 changes: 33 additions & 10 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,22 @@ macro_rules! parse_response {
};
}

fn api_url(base: &Url, endpoint: &str) -> Url {
let mut api_url = base.clone();
api_url.set_path(&format!("{VERSION}/{endpoint}"));
api_url
}

struct ClientInner {
cfg: Config,
http: Option<reqwest::Client>,
cache: Option<BitlinkCache>,
}

impl ClientInner {
#[inline]
fn api_url(&self, endpoint: &str) -> Url {
self.cfg
.api_url
.join(VERSION)
.and_then(|url| url.join(endpoint))
.expect("invalid endpoint URL")
api_url(&self.cfg.api_url, endpoint)
}

async fn fetch_user(&self) -> Result<User> {
Expand All @@ -107,8 +110,14 @@ impl ClientInner {
.send()
.await?;

parse_response! {
resp => OK || FORBIDDEN | NOT_FOUND | INTERNAL_SERVER_ERROR | SERVICE_UNAVAILABLE
parse_response! { resp =>
OK
||
FORBIDDEN
| GONE
| NOT_FOUND
| INTERNAL_SERVER_ERROR
| SERVICE_UNAVAILABLE
}
}

Expand Down Expand Up @@ -161,6 +170,7 @@ impl ClientInner {
||
BAD_REQUEST
| FORBIDDEN
| GONE
| EXPECTATION_FAILED
| UNPROCESSABLE_ENTITY
| TOO_MANY_REQUESTS
Expand Down Expand Up @@ -403,7 +413,7 @@ mod tests {
let ServerConfig { server, config } = server_config;

Mock::given(method("POST"))
.and(path("/shorten"))
.and(path("v4/shorten"))
.respond_with(responder)
.mount(&server)
.await;
Expand Down Expand Up @@ -431,7 +441,7 @@ mod tests {
let ServerConfig { server, config } = server_config;

Mock::given(method("POST"))
.and(path("/shorten"))
.and(path("v4/shorten"))
.respond_with(responder)
.mount(&server)
.await;
Expand All @@ -456,7 +466,7 @@ mod tests {
.set_body_raw(r#"{"message": "FORBIDDEN"}"#, "application/json");

Mock::given(method("POST"))
.and(path("/shorten"))
.and(path("v4/shorten"))
.respond_with(forbidden)
.mount(&server)
.await;
Expand All @@ -471,4 +481,17 @@ mod tests {
}

// TODO: test with caching enabled and --offline

#[rstest]
#[case::shorten(
"https://api-ssl.bitly.com",
"shorten",
"https://api-ssl.bitly.com/v4/shorten"
)]
fn make_api_url(#[case] base: &str, #[case] endpoint: &str, #[case] expected: &str) {
let base = Url::parse(base).unwrap();
let expected = Url::parse(expected).unwrap();
let actual = api_url(&base, endpoint);
assert_eq!(expected, actual);
}
}

0 comments on commit 0ffff1e

Please sign in to comment.