fml/
types.rs

1use crate::{
2    Error,
3    FmlResult,
4};
5use serde::Deserialize;
6use std::collections::HashMap;
7
8/// An API Response
9#[derive(Deserialize)]
10pub struct ApiResponse<T> {
11    /// A potential API error.
12    ///
13    /// Populated on error.
14    pub error: Option<String>,
15
16    /// A potential response payload.
17    ///
18    /// Populated if successful.
19    pub data: Option<T>,
20
21    /// Unknown data
22    #[serde(flatten)]
23    pub unknown: HashMap<String, serde_json::Value>,
24}
25
26impl<T> ApiResponse<T> {
27    /// Whether the response is an error.
28    ///
29    /// This performs a check on the error field.
30    pub fn is_error(&self) -> bool {
31        self.error.is_some()
32    }
33
34    /// Whether the response is a success.
35    ///
36    /// This performs a check on the data field.
37    pub fn is_success(&self) -> bool {
38        self.error.is_none() && self.data.is_some()
39    }
40
41    /// Checks whether the data contained is valid.
42    ///
43    /// This looks to see if this is both an error and success or neither.
44    pub fn is_valid_response(&self) -> bool {
45        self.is_error() || self.is_success()
46    }
47}
48
49impl<T> From<ApiResponse<T>> for FmlResult<T> {
50    fn from(response: ApiResponse<T>) -> Self {
51        match (response.data, response.error) {
52            (Some(_data), Some(_e)) => Err(Error::InvalidApiResponse),
53            (Some(data), None) => Ok(data),
54            (None, Some(e)) => Err(Error::Api(e)),
55            (None, None) => Err(Error::InvalidApiResponse),
56        }
57    }
58}
59
60/// An FML article
61#[derive(Debug, Deserialize)]
62pub struct Article {
63    pub apikey: Option<String>,
64    pub area: Option<String>,
65    pub author: Option<String>,
66    pub bitly: Option<String>,
67    pub city: Option<String>,
68    pub content: String,
69    pub content_hidden: String,
70    pub country: Option<String>,
71    pub countrycode: Option<String>,
72    pub created: String,
73    pub flag: u32,
74    pub gender: Option<u8>,
75    pub id: u64,
76    pub images: Vec<ArticleImage>,
77    pub ip: Option<String>,
78    pub keywords: Vec<ArticleKeyword>,
79    pub layout: u32,
80    pub metrics: ArticleMetrics,
81    pub openview: u32,
82    pub origin: Option<String>,
83    pub paragraphs: Vec<serde_json::Value>,
84    pub published: String,
85    pub site: u32,
86    pub siteorig: Option<serde_json::Value>,
87    pub slug: String,
88    #[serde(rename = "socialTruncate")]
89    pub social_truncate: bool,
90    pub spicy: bool,
91    pub status: u32,
92    pub title: Option<String>,
93    #[serde(rename = "type")]
94    pub article_type: u32,
95    pub updated: String,
96    pub url: String,
97    pub user: u64,
98    pub usermetrics: ArticleUsermetrics,
99    pub videos: Vec<serde_json::Value>,
100    pub vote: u32,
101
102    #[serde(flatten)]
103    pub unknown: HashMap<String, serde_json::Value>,
104}
105
106#[derive(Debug, Deserialize)]
107pub struct ArticleImage {
108    pub copyright: Option<String>,
109    pub height: u32,
110    pub legend: Option<serde_json::Value>,
111    pub name: String,
112    pub url: String,
113    pub usage: u32,
114    pub width: u32,
115
116    #[serde(flatten)]
117    pub unknown: HashMap<String, serde_json::Value>,
118}
119
120#[derive(Debug, Deserialize)]
121pub struct ArticleKeyword {
122    pub label: String,
123    pub rub: bool,
124    pub uid: u32,
125
126    #[serde(flatten)]
127    pub unknown: HashMap<String, serde_json::Value>,
128}
129
130#[derive(Debug, Deserialize)]
131pub struct ArticleMetrics {
132    pub article: u64,
133    pub comment: u32,
134    pub favorite: u32,
135    pub mod_negative: u32,
136    pub mod_positive: u32,
137    pub reports: u32,
138    pub smiley_amusing: u32,
139    pub smiley_funny: u32,
140    pub smiley_hilarious: u32,
141    pub smiley_weird: u32,
142    pub votes_down: u32,
143    pub votes_up: u32,
144
145    #[serde(flatten)]
146    pub unknown: HashMap<String, serde_json::Value>,
147}
148
149#[derive(Debug, Deserialize)]
150pub struct ArticleUsermetrics {
151    pub favorite: bool,
152    pub smiley: Option<serde_json::Value>,
153    pub votes: Option<serde_json::Value>,
154    #[serde(flatten)]
155    pub unknown: HashMap<String, serde_json::Value>,
156}
157
158#[cfg(test)]
159mod test {
160    use super::*;
161
162    const DATA_1: &str = include_str!("../test_data/DATA_1.json");
163
164    #[test]
165    fn data_1() {
166        let _data_1: ApiResponse<Vec<Article>> =
167            serde_json::from_str(DATA_1).expect("failed to parse");
168    }
169}