api_adresse_rs/
lib.rs

1use reqwest::blocking;
2use std::error::Error as StdError;
3use std::fmt;
4use std::result;
5use serde::{Serialize, Deserialize};
6
7const API_URL_SEARCH : &'static str = "https://api-adresse.data.gouv.fr/search/?q=";
8const API_URL_REVERSE : &'static str = "https://api-adresse.data.gouv.fr/reverse/?";
9
10#[derive(Debug)]
11pub enum Error {
12    HttpError,
13    GetTextError,
14    UnmarshalJsonError,
15}
16
17impl StdError for Error {}
18
19impl fmt::Display for Error {
20    fn fmt(&self, f: &mut fmt::Formatter <'_>) -> fmt::Result {
21        match &*self {
22            HttpError => write!(f, "Can't access to http://api-adresse.data.gouv.fr"),
23            GetTextError => write!(f, "Can't unmarshal data response to text"),
24            UnmarshalJsonError => write!(f, "Can't unmarshal text response to json")
25        }
26    }
27}
28
29#[derive(Serialize, Deserialize, Debug)]
30pub struct AddressResult {
31    pub r#type: String,
32    pub version: String,
33    pub features: Vec<Feature>
34}
35
36#[derive(Serialize, Deserialize, Debug)]
37pub struct Feature {
38    pub r#type: String,
39    pub geometry: Geometry,
40    pub properties: Properties
41}
42
43#[derive(Serialize, Deserialize, Debug)]
44pub struct Geometry {
45    pub r#type: String,
46    pub coordinates: Coordinates
47}
48
49#[derive(Serialize, Deserialize, Debug)]
50pub struct Coordinates {
51    #[serde(rename = "0")]
52    pub lat: f64,
53    #[serde(rename = "1")]
54    pub lon: f64
55}
56
57#[derive(Serialize, Deserialize, Debug)]
58pub struct Properties {
59    pub label: String,
60    pub score: f64,
61    pub housenumber: Option<String>,
62    pub id: String,
63    pub r#type: String,
64    pub x: f64,
65    pub y: f64,
66    pub importance: f64,
67    pub name: String,
68    pub postcode: String,
69    pub citycode: String,
70    pub context: String,
71    pub street: Option<String>
72}
73
74fn get_data(url: &str) -> Result<AddressResult, Error> {
75    let response = match blocking::get(url) {
76        Ok(value) => value,
77        _ => return Err(Error::HttpError)
78    };
79
80    let value = match response.text() {
81        Ok(value) => value,
82        _ => return Err(Error::GetTextError)
83    };
84
85    let data: AddressResult = match serde_json::from_str(&value) {
86        Ok(value) => value,
87        _ => return Err(Error::UnmarshalJsonError)
88    };
89    Ok(data)
90
91}
92
93pub fn get_address_info(search: &str) -> Result<AddressResult, Error>  {
94    let url = format!("{}{}", API_URL_SEARCH, search);
95    get_data(&*url)
96}
97
98pub fn get_reverse_info(lon: f64, lat: f64) -> Result<AddressResult, Error> {
99    let url = format!("{}lon={}&lat={}", API_URL_REVERSE, lon, lat);
100    get_data(&*url)
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106    #[test]
107    fn test_get_address_info() {
108        let result =  get_address_info("200 Chemin de puy petit").unwrap();
109        assert_eq!(result.features[0].properties.postcode, "26270");
110        assert_eq!(result.features[0].properties.citycode, "26166");
111    }
112
113    #[test]
114    fn test_get_reverse_info() {
115        let result = get_reverse_info(2.37, 48.357).unwrap();
116        assert_eq!(result.features[0].properties.label, "23 Chemin de Pithiviers 91720 Prunay-sur-Essonne");
117    }
118}