Skip to content
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

Issue #132 - Added needed routes for geolocate #133

Merged
merged 13 commits into from
Mar 14, 2024
Merged

Conversation

alexcottner
Copy link
Contributor

@alexcottner alexcottner commented Dec 21, 2023

This relates to the retirement of the Mozilla Location Service. We still rely on some (very limited) functionality so we'll be porting that over to classify-client.

Added routes for issue #132 . Added unit tests for country endpoint.
Didn't add unit tests for canned responses as that seemed excessive, but can add if we think that's useful.

This is first rust work, so please be nitpicky but detailed. But I think me and rust are gonna get along great.

This relies on writing a file in the deployment process that contains the valid API keys for the /api/v1/country route.

Note: Pulled in changes from #135 because circle-ci wasn't working right.

Copy link
Contributor

@leplatrem leplatrem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think me and rust are gonna get along great.

🤩

let mut response = HttpResponse::Ok();
response.append_header((
http::header::CACHE_CONTROL,
"max-age=0, no-cache, no-store, must-revalidate",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we set these? Can we explicit in a comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mirrored logic from classify_client. I'm guessing this is so requests are re-made every time in case addresses change, but that is speculation. Will investigate.

"max-age=0, no-cache, no-store, must-revalidate",
));

let country = location.unwrap().country.unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can unwrap location because we have a branch when it's none.
But what if country is none here? Don't we want to cover that branch above to return not found if country is none?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix

let country = location.unwrap().country.unwrap();
response.json(CountryResponse {
country_code: country.iso_code.unwrap(),
country_name: country.names.unwrap()["en"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to panic, so we have to avoid using unwrap here.

We may want to use .unwrap_or("default")

or

country_name: match country.names {
   Some(v) => v["en"],
   None => ""
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda don't like that this is a struct where all props are Options, seems very messy but that is an upstream thing. I'll try to make it as readable as possible.

country_name: country.names.unwrap()["en"],
})
})
.map_err(|err| ClassifyError::from_source("Future failure", err));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's a "future failure"?

Copy link
Contributor Author

@alexcottner alexcottner Jan 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was mirroring the logic from classify_client but I'm not sure why. I don't think we should even be able to hit this error.

assert_eq!(
miss_response.status(),
404,
"Geoip should return 404 http status for an unknown IP"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this specification really part of the endpoint?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, yes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if there's no explicit code for it, right? You are checking here that it also applies to this endpoint I guess

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, we actually do return 404 specifically up on line 49.

struct CountryNotFoundError<'a> {
domain: &'a str,
reason: &'a str,
message: &'a str,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(not sure) Are lifetimes necessary if they are all the same as the struct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I try to remove them the compiler gets upset with me. Will look into a bit more.

assert_eq!(
miss_response.status(),
404,
"Geoip should return 404 http status for an unknown IP"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if there's no explicit code for it, right? You are checking here that it also applies to this endpoint I guess

country_code: match country.iso_code {
Some(x) => x,
None => "",
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be country.iso_code.unwrap_or("")

country_name: match country.names {
Some(x) => x["en"],
None => "",
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never know whether the short form is better in this case: country.names.and_then(|x| x["en"]);

@alexcottner alexcottner requested a review from leplatrem March 13, 2024 18:42
.insert_header(("x-forwarded-for", "127.0.0.2"))
.to_request();
println!("Request: {:?}", miss_request);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leftover :)

}
},
_ => {
return Ok(HttpResponse::Unauthorized().body(""));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

body("Missing key") ?

Ok(req_query) => match KEYS_HASHSET.lock() {
Ok(keys) => {
if !keys.contains(&req_query.key) {
return Ok(HttpResponse::Unauthorized().body(""));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

body("Wrong key")

}
}
_ => {
return Ok(HttpResponse::Unauthorized().body(""));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could want to return a 5XX if the file is not present

@@ -1,3 +1,4 @@
/target/
GeoLite2-Country.mmdb
.vscode/
apiKeys.json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this if we ship it in the repo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We ship the test file to make it easy. But we won't have the keys in the repo, they'll get merged in as the container is deployed.

@alexcottner alexcottner merged commit 03b26e7 into master Mar 14, 2024
2 of 3 checks passed
@alexcottner alexcottner deleted the geolocate branch March 14, 2024 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants