1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
extern crate serde_json;
use url::Url;
use structs::*;
use cabot::{RequestBuilder, Client};

#[derive(Deserialize, Debug, Clone)]
pub struct GoogleResponseResultGeometry {
    location: Location,
    location_type: String,
}

#[derive(Deserialize, Debug, Clone)]
pub struct GoogleResponseResult {
    geometry: GoogleResponseResultGeometry,
    formatted_address: String,
}

#[derive(Deserialize, Debug)]
pub struct GoogleResponse {
    pub results: Vec<GoogleResponseResult>,
    pub status: String,
}

pub const BASE_URL: &str = "https://maps.googleapis.com/maps/api/geocode/json";
pub const STATUS_NO_RESULTS: &str = "ZERO_RESULTS";
pub const STATUS_OK: &str = "OK";
pub const STATUS_OVER_LIMIT: &str = "OVER_QUERY_LIMIT";
pub const ERR_OVER_LIMIT: &str = "Exceeded public query limit.";
pub const ERR_NO_RESULTS: &str = "Could not find location by name.";

pub fn geocode(address: &str) -> Result<GeocodeResponse, String> {
    let mut url = Url::parse(BASE_URL).unwrap();
    url.query_pairs_mut().append_pair("address", address);
    let request = RequestBuilder::new(url.as_str())
        .set_http_method("GET")
        .build()
        .unwrap();
    let client = Client::new();
    let raw_response = client.execute(&request).unwrap();
    let response: GoogleResponse = serde_json::from_slice(
	    	raw_response.body().unwrap()
	    )
	    .unwrap();

    return match response.status.as_str() {
        STATUS_OK => Ok(GeocodeResponse {
            location: response.results[0].clone().geometry.location,
            location_type: response.results[0].clone().geometry.location_type,
            formatted_address: response.results[0].clone().formatted_address,
        }),
        STATUS_NO_RESULTS => Err(ERR_NO_RESULTS.to_string()),
        STATUS_OVER_LIMIT => Err(ERR_OVER_LIMIT.to_string()),
        _ => Err(response.status),
    };
}