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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use crate::api_client::{ApiClient, DEFAULT_PAGE_SIZE};
use crate::error::ResultApi;
use crate::model::{Post, PostsResponse};
impl ApiClient {
/// Get a single post once, without automatic retry on "not available" or HTTP 401.
///
/// # Parameters
///
/// - `blog_name`: identifier or name of the blog.
/// - `post_id`: identifier of the post.
///
/// # Returns
///
/// On success, returns the `Post` object.
///
/// # Errors
///
/// - `ApiError::Unauthorized` if the HTTP status is 401 Unauthorized.
/// - `ApiError::HttpStatus` for other non-success HTTP statuses, with status and endpoint info.
/// - `ApiError::HttpRequest` if the HTTP request fails.
/// - `ApiError::JsonParseDetailed` if the response body cannot be parsed into a `Post`.
pub async fn get_post(&self, blog_name: &str, post_id: &str) -> ResultApi<Post> {
let path = format!("blog/{blog_name}/post/{post_id}");
let response = self.get_request(&path).await?;
let response = self.handle_response(&path, response).await?;
self.parse_json(response).await
}
// pub async fn get_posts(&self, blog_name: &str, limit: usize) -> ResultApi<PostsResponse> {
// let path = format!("blog/{blog_name}/post/?limit={limit}");
// let response = self.get_request(&path).await?;
// let status = response.status();
// if status == 401 {
// return Err(ApiError::Unauthorized);
// }
// let posts_response = response
// .json::<PostsResponse>()
// .await
// .map_err(ApiError::JsonParse)?;
// Ok(posts_response)
// }
/// Get multiple posts for a blog.
///
/// # Parameters
///
/// - `blog_name`: blog identifier/name.
/// - `limit`: number of posts to fetch.
/// - `page_size`: number of posts to fetch per page. Defaults to 20.
/// - `start_offset`: offset to start fetching posts from. Defaults from first post.
///
/// # Returns
///
/// On success, returns a `PostsResponse` containing the `data` field with `Post` items.
///
/// # Errors
///
/// - `ApiError::HttpRequest` if the HTTP request fails.
/// - `ApiError::JsonParse` if the HTTP response cannot be parsed as JSON.
/// - `ApiError::Deserialization` if the `"data"` field cannot be deserialized into a vector of `Post`
pub async fn get_posts(
&self,
blog_name: &str,
limit: usize,
page_size: Option<usize>,
start_offset: Option<String>,
) -> ResultApi<Vec<Post>> {
let page_size = page_size.unwrap_or(DEFAULT_PAGE_SIZE);
let mut all_posts = Vec::new();
let mut offset = start_offset;
loop {
let current_limit = page_size.min(limit - all_posts.len());
let mut path = format!("blog/{blog_name}/post/?limit={current_limit}");
if let Some(ref off) = offset {
path.push_str(&format!("&offset={off}"));
}
let response = self.get_request(&path).await?;
let response = self.handle_response(&path, response).await?;
let posts_response: PostsResponse = self.parse_json(response).await?;
let data_len = posts_response.data.len();
all_posts.extend(posts_response.data);
if posts_response.extra.is_last || all_posts.len() >= limit || data_len == 0 {
break;
}
offset = Some(posts_response.extra.offset);
}
Ok(all_posts)
}
}