notion_wasi/backend/
mod.rs

1use crate::ids::{AsIdentifier, BlockId, DatabaseId, PageId};
2use crate::models::{
3    block::Block,
4    search::{DatabaseQuery, SearchRequest},
5    Database, ListResponse, Object, Page, PageCreateRequest,
6};
7use async_trait::async_trait;
8
9#[cfg(not(target_os = "wasi"))]
10mod reqwest_impl;
11
12#[cfg(not(target_os = "wasi"))]
13pub use reqwest_impl::{Client, Error};
14
15#[cfg(target_os = "wasi")]
16mod http_req_impl;
17
18#[cfg(target_os = "wasi")]
19pub use http_req_impl::{Client, Error};
20
21pub type Result<T> = std::result::Result<T, Error>;
22
23#[async_trait]
24pub trait TClient {
25    async fn get<S: Into<String> + Send>(
26        &self,
27        uri: S,
28    ) -> Result<Object>;
29
30    async fn post<S: Into<String> + Send>(
31        &self,
32        uri: S,
33    ) -> Result<Object>;
34
35    async fn post_json<S: Into<String> + Send>(
36        &self,
37        uri: S,
38        body: &[u8],
39    ) -> Result<Object>;
40}
41
42pub struct NotionApi {
43    client: Client,
44}
45
46impl NotionApi {
47    pub fn new<S: Into<String>>(api_token: S) -> Result<Self> {
48        let client = Client::new(api_token.into())?;
49
50        Ok(Self { client })
51    }
52}
53
54impl NotionApi {
55    /// List all the databases shared with the supplied integration token.
56    /// > This method is apparently deprecated/"not recommended" and
57    /// > [search()](Self::search()) should be used instead.
58    pub async fn list_databases(&self) -> Result<ListResponse<Database>> {
59        match self
60            .client
61            .get("https://api.notion.com/v1/databases")
62            .await?
63        {
64            Object::List { list } => Ok(list.expect_databases()?),
65            response => Err(Error::UnexpectedResponse { response }),
66        }
67    }
68
69    /// Search all pages in notion.
70    /// `query` can either be a [SearchRequest] or a slightly more convenient
71    /// [NotionSearch](models::search::NotionSearch) query.
72    pub async fn search<T: Into<SearchRequest>>(
73        &self,
74        query: T,
75    ) -> Result<ListResponse<Object>> {
76        let query = serde_json::to_string(&query.into()).unwrap();
77
78        let result = self
79            .client
80            .post_json("https://api.notion.com/v1/search", query.as_bytes())
81            .await?;
82
83        match result {
84            Object::List { list } => Ok(list),
85            response => Err(Error::UnexpectedResponse { response }),
86        }
87    }
88
89    /// Get a database by [DatabaseId].
90    pub async fn get_database<T: AsIdentifier<DatabaseId>>(
91        &self,
92        database_id: T,
93    ) -> Result<Database> {
94        let uri = format!(
95            "https://api.notion.com/v1/databases/{}",
96            database_id.as_id()
97        );
98        let result = self.client.get(uri).await?;
99
100        match result {
101            Object::Database { database } => Ok(database),
102            response => Err(Error::UnexpectedResponse { response }),
103        }
104    }
105
106    /// Get a page by [PageId].
107    pub async fn get_page<T: AsIdentifier<PageId>>(
108        &self,
109        page_id: T,
110    ) -> Result<Page> {
111        let uri = format!("https://api.notion.com/v1/pages/{}", page_id.as_id());
112        let result = self.client.get(uri).await?;
113
114        match result {
115            Object::Page { page } => Ok(page),
116            response => Err(Error::UnexpectedResponse { response }),
117        }
118    }
119
120    /// Creates a new page and return the created page
121    pub async fn create_page<T: Into<PageCreateRequest>>(
122        &self,
123        page: T,
124    ) -> Result<Page> {
125        let page = serde_json::to_string(&page.into()).unwrap();
126
127        let result = self
128            .client
129            .post_json("https://api.notion.com/v1/pages", page.as_bytes())
130            .await?;
131
132        match result {
133            Object::Page { page } => Ok(page),
134            response => Err(Error::UnexpectedResponse { response }),
135        }
136    }
137
138    /// Query a database and return the matching pages.
139    pub async fn query_database<D, T>(
140        &self,
141        database: D,
142        query: T,
143    ) -> Result<ListResponse<Page>>
144    where
145        T: Into<DatabaseQuery>,
146        D: AsIdentifier<DatabaseId>,
147    {
148        let query = serde_json::to_string(&query.into()).unwrap();
149
150        let uri = format!(
151            "https://api.notion.com/v1/databases/{database_id}/query",
152            database_id = database.as_id()
153        );
154
155        let result = self.client.post_json(uri, query.as_bytes()).await?;
156
157        match result {
158            Object::List { list } => Ok(list.expect_pages()?),
159            response => Err(Error::UnexpectedResponse { response }),
160        }
161    }
162
163    pub async fn get_block_children<T: AsIdentifier<BlockId>>(
164        &self,
165        block_id: T,
166    ) -> Result<ListResponse<Block>> {
167        let uri = format!(
168            "https://api.notion.com/v1/blocks/{block_id}/children",
169            block_id = block_id.as_id()
170        );
171
172        let result = self.client.get(uri).await?;
173
174        match result {
175            Object::List { list } => Ok(list.expect_blocks()?),
176            response => Err(Error::UnexpectedResponse { response }),
177        }
178    }
179}