aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--src/lib.rs56
-rw-r--r--src/models/properties.rs4
-rw-r--r--src/models/search.rs26
4 files changed, 56 insertions, 31 deletions
diff --git a/Cargo.toml b/Cargo.toml
index a763aa5..8d53ed4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,7 @@ license = "MIT"
[dependencies]
serde_json = "1.0.64"
+snafu = "0.6.10"
[dependencies.chrono]
version = "0.4.19"
diff --git a/src/lib.rs b/src/lib.rs
index c97ee48..c74aadf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,13 +3,29 @@ use crate::models::{Database, DatabaseId, ListResponse, Object, Page};
use reqwest::header::{HeaderMap, HeaderValue};
use reqwest::{header, Client, ClientBuilder, RequestBuilder};
use serde::de::DeserializeOwned;
+use snafu::{ResultExt, Snafu};
mod models;
-const NOTION_API_VERSION: &'static str = "2021-05-13";
+const NOTION_API_VERSION: &str = "2021-05-13";
-// todo: replace with proper snafu error
-pub type NotionApiClientError = Box<dyn std::error::Error>;
+#[derive(Debug, Snafu)]
+pub enum Error {
+ #[snafu(display("Invalid Notion API Token: {}", source))]
+ InvalidApiToken {
+ source: reqwest::header::InvalidHeaderValue,
+ },
+ #[snafu(display("Unable to build reqwest HTTP client: {}", source))]
+ ErrorBuildingClient { source: reqwest::Error },
+ #[snafu(display("Error sending HTTP request: {}", source))]
+ RequestFailed { source: reqwest::Error },
+
+ #[snafu(display("Error reading response: {}", source))]
+ ResponseError { source: reqwest::Error },
+
+ #[snafu(display("Error parsing json response: {}", source))]
+ JsonParseError { source: serde_json::Error },
+}
pub trait Identifiable {
// There should only be one way to identify an object
@@ -22,40 +38,48 @@ pub struct NotionApi {
}
impl NotionApi {
- pub fn new(api_token: String) -> Result<Self, NotionApiClientError> {
+ pub fn new(api_token: String) -> Result<Self, Error> {
let mut headers = HeaderMap::new();
headers.insert(
"Notion-Version",
HeaderValue::from_static(NOTION_API_VERSION),
);
- let mut auth_value = HeaderValue::from_str(&format!("Bearer {}", api_token))?;
+ let mut auth_value =
+ HeaderValue::from_str(&format!("Bearer {}", api_token)).context(InvalidApiToken)?;
auth_value.set_sensitive(true);
headers.insert(header::AUTHORIZATION, auth_value);
- let client = ClientBuilder::new().default_headers(headers).build()?;
+ let client = ClientBuilder::new()
+ .default_headers(headers)
+ .build()
+ .context(ErrorBuildingClient)?;
Ok(Self { client })
}
- async fn make_json_request<T>(request: RequestBuilder) -> Result<T, NotionApiClientError>
+ async fn make_json_request<T>(request: RequestBuilder) -> Result<T, Error>
where
T: DeserializeOwned,
{
- let json = request.send().await?.text().await?;
+ let json = request
+ .send()
+ .await
+ .context(RequestFailed)?
+ .text()
+ .await
+ .context(ResponseError)?;
#[cfg(test)]
{
println!("JSON: {}", json);
- dbg!(serde_json::from_str::<serde_json::Value>(&json)?);
+ dbg!(serde_json::from_str::<serde_json::Value>(&json).context(JsonParseError)?);
}
- let result = serde_json::from_str(&json)?;
+ let result = serde_json::from_str(&json).context(JsonParseError)?;
Ok(result)
}
/// This method is apparently deprecated/"not recommended"
- pub async fn list_databases(
- &self,
- ) -> Result<ListResponse<Database>, Box<dyn std::error::Error>> {
+ pub async fn list_databases(&self) -> Result<ListResponse<Database>, Error> {
let builder = self.client.get("https://api.notion.com/v1/databases");
Ok(NotionApi::make_json_request(builder).await?)
@@ -64,7 +88,7 @@ impl NotionApi {
pub async fn search<T: Into<SearchRequest>>(
&self,
query: T,
- ) -> Result<ListResponse<Object>, NotionApiClientError> {
+ ) -> Result<ListResponse<Object>, Error> {
Ok(NotionApi::make_json_request(
self.client
.post("https://api.notion.com/v1/search")
@@ -76,7 +100,7 @@ impl NotionApi {
pub async fn get_database<T: Identifiable<Type = DatabaseId>>(
&self,
database_id: T,
- ) -> Result<Database, NotionApiClientError> {
+ ) -> Result<Database, Error> {
Ok(NotionApi::make_json_request(self.client.get(format!(
"https://api.notion.com/v1/databases/{}",
database_id.id().id()
@@ -88,7 +112,7 @@ impl NotionApi {
&self,
database: D,
query: T,
- ) -> Result<ListResponse<Page>, NotionApiClientError>
+ ) -> Result<ListResponse<Page>, Error>
where
T: Into<DatabaseQuery>,
D: Identifiable<Type = DatabaseId>,
diff --git a/src/models/properties.rs b/src/models/properties.rs
index c55ce1a..22689e9 100644
--- a/src/models/properties.rs
+++ b/src/models/properties.rs
@@ -157,7 +157,7 @@ pub enum PropertyConfiguration {
Checkbox { id: PropertyId },
/// Represents a URL Property
/// See https://developers.notion.com/reference/database#url-configuration
- URL { id: PropertyId },
+ Url { id: PropertyId },
/// Represents a Email Property
/// See https://developers.notion.com/reference/database#email-configuration
Email { id: PropertyId },
@@ -292,7 +292,7 @@ pub enum PropertyValue {
id: PropertyId,
checkbox: bool,
},
- URL {
+ Url {
id: PropertyId,
url: String,
},
diff --git a/src/models/search.rs b/src/models/search.rs
index 6acf847..6de3c8a 100644
--- a/src/models/search.rs
+++ b/src/models/search.rs
@@ -19,13 +19,6 @@ pub enum SortTimestamp {
#[derive(Serialize, Debug, Eq, PartialEq, Hash, Copy, Clone)]
#[serde(rename_all = "snake_case")]
-pub enum DatabaseSortTimestamp {
- CreatedTime,
- LastEditedTime,
-}
-
-#[derive(Serialize, Debug, Eq, PartialEq, Hash, Copy, Clone)]
-#[serde(rename_all = "snake_case")]
pub enum FilterValue {
Page,
Database,
@@ -276,15 +269,22 @@ pub struct FilterCondition {
pub condition: PropertyCondition,
}
+#[derive(Serialize, Debug, Eq, PartialEq, Hash, Copy, Clone)]
+#[serde(rename_all = "snake_case")]
+pub enum DatabaseSortTimestamp {
+ CreatedTime,
+ LastEditedTime,
+}
+
#[derive(Serialize, Debug, Eq, PartialEq, Clone)]
pub struct DatabaseSort {
// Todo: Should property and timestamp be mutually exclusive? (i.e a flattened enum?)
// the documentation is not clear:
// https://developers.notion.com/reference/post-database-query#post-database-query-sort
- property: Option<String>,
+ pub property: Option<String>,
/// The name of the timestamp to sort against.
- timestamp: Option<SortTimestamp>,
- direction: SortDirection,
+ pub timestamp: Option<DatabaseSortTimestamp>,
+ pub direction: SortDirection,
}
#[derive(Serialize, Debug, Eq, PartialEq, Default)]
@@ -322,13 +322,13 @@ impl From<NotionSearch> for SearchRequest {
timestamp,
} => SearchRequest {
sort: Some(Sort {
- direction,
timestamp,
+ direction,
}),
..Default::default()
},
- NotionSearch::Filter { value, property } => SearchRequest {
- filter: Some(Filter { value, property }),
+ NotionSearch::Filter { property, value } => SearchRequest {
+ filter: Some(Filter { property, value }),
..Default::default()
},
}