Skip to main content

auraxis/api/
response.rs

1use reqwest::Response;
2use serde::{de::IgnoredAny, de::Visitor, Deserialize};
3
4use crate::AuraxisError;
5
6#[derive(Debug)]
7pub struct CensusResponse {
8    pub items: Vec<serde_json::Value>,
9    pub count: u32,
10}
11
12impl<'de> Deserialize<'de> for CensusResponse {
13    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
14    where
15        D: serde::Deserializer<'de>,
16    {
17        deserializer.deserialize_map(CensusResponseVisitor)
18    }
19}
20
21struct CensusResponseVisitor;
22
23impl<'de> Visitor<'de> for CensusResponseVisitor {
24    type Value = CensusResponse;
25
26    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
27        write!(
28            formatter,
29            "a map with keys '<collection>_list>' and 'returned'"
30        )
31    }
32
33    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
34    where
35        A: serde::de::MapAccess<'de>,
36    {
37        let mut items = None;
38        let mut count = None;
39
40        while let Some(k) = map.next_key::<&str>()? {
41            if k == "returned" {
42                count = Some(map.next_value()?);
43            } else if k.ends_with("_list") {
44                items = Some(map.next_value()?);
45            } else {
46                let _ = map.next_value::<IgnoredAny>()?;
47            }
48        }
49
50        let items =
51            items.ok_or_else(|| serde::de::Error::custom("Missing collection_list or count"))?;
52        let count =
53            count.ok_or_else(|| serde::de::Error::custom("Missing collection_list or count"))?;
54
55        Ok(CensusResponse { items, count })
56    }
57}
58
59impl CensusResponse {
60    pub async fn from_response(response: Response) -> Result<Self, AuraxisError> {
61        Ok(response.json::<CensusResponse>().await?)
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::CensusResponse;
68
69    #[test]
70    fn ignores_extra_metadata_keys() {
71        let response = serde_json::from_str::<CensusResponse>(
72            r#"{
73                "character_list": [{"character_id": "1"}],
74                "returned": 1,
75                "timing": {"query": "1.23"},
76                "errorCode": "ok"
77            }"#,
78        )
79        .expect("response should deserialize");
80
81        assert_eq!(response.count, 1);
82        assert_eq!(response.items.len(), 1);
83    }
84}