ofdb_seed/
api.rs

1use ofdb_boundary::*;
2use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
3use seed::browser::fetch::{fetch, Header, Method, Request, Result};
4
5/// OpenFairDB API
6#[derive(Debug, Clone)]
7pub struct Api {
8    url: String,
9}
10
11impl Api {
12    pub fn new(url: String) -> Self {
13        Self { url }
14    }
15    pub async fn search(&self, txt: &str, bbox: &MapBbox) -> Result<SearchResponse> {
16        let encoded_txt = utf8_percent_encode(txt, NON_ALPHANUMERIC);
17        let MapBbox { sw, ne } = bbox;
18        let bbox_str = format!("{},{},{},{}", sw.lat, sw.lng, ne.lat, ne.lng);
19        let url = format!("{}/search?text={}&bbox={}", self.url, encoded_txt, bbox_str);
20        let response = fetch(url).await?;
21        response
22            .check_status()? // ensure we've got 2xx status
23            .json()
24            .await
25    }
26    pub async fn places(&self, ids: &[String]) -> Result<Vec<Entry>> {
27        let ids = ids.join(",");
28        let url = format!("{}/entries/{}", self.url, ids);
29        let response = fetch(url).await?;
30        response
31            .check_status()? // ensure we've got 2xx status
32            .json()
33            .await
34    }
35    pub async fn create_place(&self, place: &NewPlace) -> Result<()> {
36        let url = format!("{}/entries", self.url);
37        let request = Request::new(url).method(Method::Post).json(place)?;
38        let response = fetch(request).await?;
39        response.check_status()?; // ensure we've got 2xx status
40        Ok(())
41    }
42    pub async fn update_place(&self, id: &str, place: &UpdatePlace) -> Result<()> {
43        let url = format!("{}/entries/{}", self.url, id);
44        let request = Request::new(url).method(Method::Put).json(place)?;
45        let response = fetch(request).await?;
46        response.check_status()?; // ensure we've got 2xx status
47        Ok(())
48    }
49    pub async fn get_places_clearance_with_api_token(
50        &self,
51        api_token: &str,
52    ) -> Result<Vec<PendingClearanceForPlace>> {
53        let url = format!("{}/places/clearance", self.url);
54        let request = Request::new(url)
55            .method(Method::Get)
56            .header(Header::bearer(api_token));
57        let response = fetch(request).await?;
58        let result = response.check_status()?.json().await?;
59        Ok(result)
60    }
61    pub async fn get_place_history_with_api_token(
62        &self,
63        api_token: &str,
64        id: &str,
65    ) -> Result<PlaceHistory> {
66        let url = format!("{}/places/{}/history", self.url, id);
67        let request = Request::new(url)
68            .method(Method::Get)
69            .header(Header::bearer(api_token));
70        let response = fetch(request).await?;
71        let result = response
72            .check_status()? // ensure we've got 2xx status
73            .json()
74            .await?;
75        Ok(result)
76    }
77    pub async fn post_places_clearance_with_api_token(
78        &self,
79        api_token: &str,
80        clearances: Vec<ClearanceForPlace>,
81    ) -> Result<ResultCount> {
82        let url = format!("{}/places/clearance", self.url);
83        let request = Request::new(url)
84            .method(Method::Post)
85            .header(Header::bearer(api_token))
86            .json(&clearances)?;
87        let response = fetch(request).await?;
88        let result = response
89            .check_status()? // ensure we've got 2xx status
90            .json()
91            .await?;
92        Ok(result)
93    }
94    pub async fn post_login(&self, req: &Credentials) -> Result<()> {
95        let url = format!("{}/login", self.url);
96        let request = Request::new(url)
97            .credentials(web_sys::RequestCredentials::Include)
98            .method(Method::Post)
99            .json(&req)?;
100        let response = fetch(request).await?;
101        response.check_status()?; // ensure we've got 2xx status
102        Ok(())
103    }
104    pub async fn post_logout(&self) -> Result<()> {
105        let url = format!("{}/logout", self.url);
106        let request = Request::new(url)
107            .method(Method::Post)
108            .credentials(web_sys::RequestCredentials::Include)
109            .json(&())?;
110        let response = fetch(request).await?;
111        response.check_status()?; // ensure we've got 2xx status
112        Ok(())
113    }
114    pub async fn get_users_current(&self) -> Result<User> {
115        let url = format!("{}/users/current", self.url);
116        let request = Request::new(url)
117            .method(Method::Get)
118            .credentials(web_sys::RequestCredentials::Include);
119        let response = fetch(request).await?;
120        let result = response
121            .check_status()? // ensure we've got 2xx status
122            .json()
123            .await?;
124        Ok(result)
125    }
126    pub async fn get_tags(&self) -> Result<Vec<String>> {
127        let url = format!("{}/tags", self.url);
128        let request = Request::new(url).method(Method::Get);
129        let response = fetch(request).await?;
130        let result = response
131            .check_status()? // ensure we've got 2xx status
132            .json()
133            .await?;
134        Ok(result)
135    }
136    pub async fn get_most_popular_tags(
137        &self,
138        min_count: Option<usize>,
139        max_count: Option<usize>,
140        limit: Option<usize>,
141        offset: Option<usize>,
142    ) -> Result<Vec<TagFrequency>> {
143        let mut url = format!("{}/entries/most-popular-tags", self.url);
144        if min_count.or(max_count).or(limit).or(offset).is_some() {
145            url = format!("{}?", url);
146            if let Some(cnt) = min_count {
147                url = format!("{}&min_count={}", url, cnt);
148            }
149            if let Some(cnt) = max_count {
150                url = format!("{}&max_count={}", url, cnt);
151            }
152            if let Some(l) = limit {
153                url = format!("{}&limit={}", url, l);
154            }
155            if let Some(o) = offset {
156                url = format!("{}&offset={}", url, o);
157            }
158        }
159        let request = Request::new(url).method(Method::Get);
160        let response = fetch(request).await?;
161        let result = response
162            .check_status()? // ensure we've got 2xx status
163            .json()
164            .await?;
165        Ok(result)
166    }
167}