Even better leniant parsing
This commit is contained in:
parent
fbcc5d536e
commit
f1a0944688
|
@ -0,0 +1 @@
|
||||||
|
{"nItems":0,"nPages":0,"items":[],"_links":[{"href":"/api/v1/project/vogon","rel":"project","type":"GET"},{"href":"/api/v1/project/vogon/posts?page=998","rel":"prev","type":"GET"}]}
|
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,5 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
pub fn cohost_posts_api_url(project: impl AsRef<str>, page: u64) -> String {
|
pub fn cohost_posts_api_url(project: impl AsRef<str>, page: u64) -> String {
|
||||||
format!(
|
format!(
|
||||||
|
@ -11,7 +11,7 @@ pub fn cohost_posts_api_url(project: impl AsRef<str>, page: u64) -> String {
|
||||||
|
|
||||||
// Cohost doesn't give us Next links ("rel: next") for further pages, so we'll have to ALWAYS populate the rel=next field
|
// Cohost doesn't give us Next links ("rel: next") for further pages, so we'll have to ALWAYS populate the rel=next field
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct CohostPostsPage {
|
pub struct CohostPostsPage {
|
||||||
#[serde(rename = "nItems")]
|
#[serde(rename = "nItems")]
|
||||||
pub number_items: usize,
|
pub number_items: usize,
|
||||||
|
@ -22,19 +22,27 @@ pub struct CohostPostsPage {
|
||||||
pub links: Vec<CohostPostLink>,
|
pub links: Vec<CohostPostLink>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct CohostPost {
|
pub struct CohostPost {
|
||||||
#[serde(rename = "postId")]
|
#[serde(rename = "postId")]
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
#[serde(default)]
|
#[serde(deserialize_with = "deserialize_null_default", default)]
|
||||||
pub headline: String,
|
pub headline: String,
|
||||||
#[serde(rename = "publishedAt")]
|
#[serde(rename = "publishedAt")]
|
||||||
pub published_at: DateTime<Utc>,
|
pub published_at: DateTime<Utc>,
|
||||||
pub cws: Vec<String>,
|
pub cws: Vec<String>,
|
||||||
pub tags: Vec<String>,
|
pub tags: Vec<String>,
|
||||||
#[serde(rename = "plainTextBody", default)]
|
#[serde(
|
||||||
|
rename = "plainTextBody",
|
||||||
|
deserialize_with = "deserialize_null_default",
|
||||||
|
default
|
||||||
|
)]
|
||||||
pub plain_body: String,
|
pub plain_body: String,
|
||||||
#[serde(rename = "singlePostPageUrl")]
|
#[serde(
|
||||||
|
rename = "singlePostPageUrl",
|
||||||
|
deserialize_with = "deserialize_null_default",
|
||||||
|
default
|
||||||
|
)]
|
||||||
pub url: String,
|
pub url: String,
|
||||||
#[serde(rename = "postingProject")]
|
#[serde(rename = "postingProject")]
|
||||||
pub poster: CohostPostingProject,
|
pub poster: CohostPostingProject,
|
||||||
|
@ -42,31 +50,49 @@ pub struct CohostPost {
|
||||||
pub share_tree: Vec<CohostPost>,
|
pub share_tree: Vec<CohostPost>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct CohostPostingProject {
|
pub struct CohostPostingProject {
|
||||||
#[serde(rename = "projectId")]
|
#[serde(rename = "projectId")]
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
|
#[serde(deserialize_with = "deserialize_null_default", default)]
|
||||||
pub handle: String,
|
pub handle: String,
|
||||||
#[serde(rename = "displayName", default)]
|
#[serde(
|
||||||
|
rename = "displayName",
|
||||||
|
deserialize_with = "deserialize_null_default",
|
||||||
|
default
|
||||||
|
)]
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
#[serde(default)]
|
#[serde(deserialize_with = "deserialize_null_default", default)]
|
||||||
pub dek: String,
|
pub dek: String,
|
||||||
#[serde(default)]
|
#[serde(deserialize_with = "deserialize_null_default", default)]
|
||||||
pub description: String,
|
pub description: String,
|
||||||
#[serde(default)]
|
#[serde(deserialize_with = "deserialize_null_default", default)]
|
||||||
pub pronouns: String,
|
pub pronouns: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct CohostPostLink {
|
pub struct CohostPostLink {
|
||||||
#[serde(default)]
|
#[serde(deserialize_with = "deserialize_null_default", default)]
|
||||||
pub href: String,
|
pub href: String,
|
||||||
#[serde(default)]
|
#[serde(deserialize_with = "deserialize_null_default", default)]
|
||||||
pub rel: String,
|
pub rel: String,
|
||||||
#[serde(rename = "type", default)]
|
#[serde(
|
||||||
|
rename = "type",
|
||||||
|
deserialize_with = "deserialize_null_default",
|
||||||
|
default
|
||||||
|
)]
|
||||||
pub t_type: String,
|
pub t_type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
|
||||||
|
where
|
||||||
|
T: Default + Deserialize<'de>,
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let opt = Option::deserialize(deserializer)?;
|
||||||
|
Ok(opt.unwrap_or_default())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_deserialize() -> Result<(), Box<dyn std::error::Error>> {
|
fn test_deserialize() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let post_page_json = include_str!("../samples/cohost/api/v1/project_posts.json");
|
let post_page_json = include_str!("../samples/cohost/api/v1/project_posts.json");
|
||||||
|
@ -77,3 +103,19 @@ fn test_deserialize() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
assert_eq!(post.poster.id, 32693);
|
assert_eq!(post.poster.id, 32693);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialize_weird() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let post_page_json = include_str!("../samples/cohost/api/v1/vogon_pathological.json");
|
||||||
|
let _post_page_actual: CohostPostsPage = serde_json::from_str(post_page_json)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialize_empty() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let post_page_json = include_str!("../samples/cohost/api/v1/empty_posts_age.json");
|
||||||
|
let post_page_actual: CohostPostsPage = serde_json::from_str(post_page_json)?;
|
||||||
|
println!("{:?}", post_page_actual);
|
||||||
|
assert!(post_page_actual.items.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue