diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 56 | ||||
-rw-r--r-- | src/models/properties.rs | 4 | ||||
-rw-r--r-- | src/models/search.rs | 26 |
3 files changed, 55 insertions, 31 deletions
@@ -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() }, } |