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
use anyhow::{anyhow, Result};
use serde_json::{json, Value};
use crate::json_util::{dig_json, JsonKey};
use crate::notion_database::{parse_database_schema, NotionDatabaseSchema};
use crate::notion_pages::{parse_notion_page_list, NotionPage};
pub struct NotionClient {
pub api_key: String,
}
impl NotionClient {
pub fn get_database(&self, database_id: &str) -> Result<NotionDatabaseSchema> {
let url = format!("https://api.notion.com/v1/databases/{0}", database_id);
let client = reqwest::blocking::Client::new();
info!("Requesting database schema. URL: {}", &url);
let resp = client
.get(url)
.header("Authorization", "Bearer ".to_string() + &self.api_key)
.header("Notion-Version", "2022-02-22")
.send()?
.json::<Value>()?;
info!("Request done.");
self.validate_response(&resp)?;
let schema = parse_database_schema(&resp)?;
info!("Database schema: {:?}", schema);
Ok(schema)
}
pub fn get_all_pages(
&self,
database_id: &str,
schema: &NotionDatabaseSchema,
) -> Result<Vec<NotionPage>> {
let url = format!("https://api.notion.com/v1/databases/{0}/query", database_id);
let client = reqwest::blocking::Client::new();
let mut next_cursor: Option<String> = None;
let mut all_pages: Vec<NotionPage> = vec![];
loop {
let mut query = json!({
"page_size": 10i32,
"sorts": [{
"timestamp": "created_time",
"direction": "ascending",
}]
});
if let Some(cursor) = (&next_cursor).as_ref() {
query
.as_object_mut()
.unwrap()
.insert("start_cursor".into(), cursor.clone().into());
}
let query_str = query.to_string();
info!("Requesting query: URL: {}, query: {}", &url, &query_str);
let resp = client
.post(&url)
.header("Authorization", "Bearer ".to_string() + &self.api_key)
.header("Notion-Version", "2022-02-22")
.header("Content-Type", "application/json")
.body(query_str)
.send()?
.json::<Value>()?;
info!("Request done.");
self.validate_response(&resp)?;
let (mut pages, _next_cursor) = parse_notion_page_list(schema, &resp)?;
info!("Pages: {:?}", pages.len());
all_pages.append(&mut pages);
next_cursor = _next_cursor;
if next_cursor.is_none() {
info!("Fetched all items.");
break;
} else {
info!("Has more items.");
}
}
Ok(all_pages)
}
fn validate_response(&self, resp: &Value) -> Result<()> {
let json_keys = vec![JsonKey::String("object")];
let object_field = dig_json(resp, &json_keys)
.and_then(|o| o.as_str())
.ok_or_else(|| anyhow!("Unexpected response from Notion API: {}", resp))?;
if object_field == "error" {
Err(anyhow!("Error response from Notion API: {}", resp,))
} else {
Ok(())
}
}
}