From 3b42f53d63518bd95acf06311333842a1c5ed80c Mon Sep 17 00:00:00 2001 From: Jess Mitchell Date: Mon, 14 Aug 2023 16:47:09 -0400 Subject: [PATCH 01/10] add new example (wip) --- examples/intro-to-notion-api/.env.example | 2 + examples/intro-to-notion-api/README.md | 51 ++++++++++++++++ .../intro-to-notion-api/basic/1-new-block.js | 36 ++++++++++++ .../basic/2-add-linked-block.js | 51 ++++++++++++++++ .../basic/3-styled-block-text.js | 58 +++++++++++++++++++ .../intermediate/1-create-a-database.js | 0 .../intermediate/2-add-page-to-database.js | 0 .../intermediate/3-query-database.js | 0 .../intermediate/4-sort-database.js | 0 examples/intro-to-notion-api/package.json | 24 ++++++++ 10 files changed, 222 insertions(+) create mode 100644 examples/intro-to-notion-api/.env.example create mode 100644 examples/intro-to-notion-api/README.md create mode 100644 examples/intro-to-notion-api/basic/1-new-block.js create mode 100644 examples/intro-to-notion-api/basic/2-add-linked-block.js create mode 100644 examples/intro-to-notion-api/basic/3-styled-block-text.js create mode 100644 examples/intro-to-notion-api/intermediate/1-create-a-database.js create mode 100644 examples/intro-to-notion-api/intermediate/2-add-page-to-database.js create mode 100644 examples/intro-to-notion-api/intermediate/3-query-database.js create mode 100644 examples/intro-to-notion-api/intermediate/4-sort-database.js create mode 100644 examples/intro-to-notion-api/package.json diff --git a/examples/intro-to-notion-api/.env.example b/examples/intro-to-notion-api/.env.example new file mode 100644 index 00000000..b8f71102 --- /dev/null +++ b/examples/intro-to-notion-api/.env.example @@ -0,0 +1,2 @@ +NOTION_API_KEY= +NOTION_PAGE_ID= \ No newline at end of file diff --git a/examples/intro-to-notion-api/README.md b/examples/intro-to-notion-api/README.md new file mode 100644 index 00000000..f1f1f24b --- /dev/null +++ b/examples/intro-to-notion-api/README.md @@ -0,0 +1,51 @@ +# Introduction to using Notion's SDK for JavaScript + +## Learn how to make public API requests + +Use this sample code to learn how to make public API requests with varying degrees of difficulty. + +The sample code is split into three sections: + +1. basic +2. intermediate +3. advanced + +If you are new to Notion's SDK for JavaScript, start with the code samples in the `/basic` directory to get more familiar to basic concepts. + +The files in each directory will build on each other to increase in complexity. For example, in `/intermediate`, first you will see how to create a database, then how to create a database and add a page to it, and finally create a database, add a page, and query the database. + +## Table of contents + +In case you are looking for a specific task, the files are divided as follows: + +- `/basic/1-new-block.js`: Create a new block that will be appended to a Notion page. +- `/basic/2-styled-block-text.js`: Update a block's text styles after creating it. +- `/intermediate/1-create-a-database.js`: Create a new database with defined properties. +- `/intermediate/2-add-page-to-database.js`: Add a new page to a newly-created database. +- `/intermediate/3-query-database.js`: Create a new database with defined properties. +- `/intermediate/3-sort-database.js`: Create a new database with defined properties. +- `/advanced/` // todo: add these - not sure what we're including + +## Run locally + +To use this example on your local machine, clone the repo and move into the cloned repo: + +```zsh +git clone https://github.com/makenotion/notion-sdk-js.git +cd /notion-sdk-js +``` + +Next, move into this example in the `/examples` directory and install its dependencies: + +```zsh +cd /examples/intro-to-notion-api +npm install +``` + +To run each individual example, use the `node` command with the file's path. + +For example: + +```zsh +node /basic/1-new-block.js +``` diff --git a/examples/intro-to-notion-api/basic/1-new-block.js b/examples/intro-to-notion-api/basic/1-new-block.js new file mode 100644 index 00000000..c1d74132 --- /dev/null +++ b/examples/intro-to-notion-api/basic/1-new-block.js @@ -0,0 +1,36 @@ +import { Client } from "@notionhq/client" +import { config } from "dotenv" + +config() + +const pageId = process.env.NOTION_PAGE_ID +const apiKey = process.env.NOTION_API_KEY + +const notion = new Client({ auth: apiKey }) + +/* +--------------------------------------------------------------------------- +*/ + +async function main() { + const blockId = pageId // Blocks can be appended to other blocks *or* pages. Therefore, a page ID can be used for the block_id parameter + const newHeadingResponse = await notion.blocks.children.append({ + block_id: blockId, + children: [ + { + heading_2: { + rich_text: [ + { + text: { + content: "Types of kale", + }, + }, + ], + }, + }, + ], + }) + console.log(newHeadingResponse) +} + +main() diff --git a/examples/intro-to-notion-api/basic/2-add-linked-block.js b/examples/intro-to-notion-api/basic/2-add-linked-block.js new file mode 100644 index 00000000..d481b786 --- /dev/null +++ b/examples/intro-to-notion-api/basic/2-add-linked-block.js @@ -0,0 +1,51 @@ +import { Client } from "@notionhq/client" +import { config } from "dotenv" + +config() + +const pageId = process.env.NOTION_PAGE_ID +const apiKey = process.env.NOTION_API_KEY + +const notion = new Client({ auth: apiKey }) + +/* +--------------------------------------------------------------------------- +*/ + +async function main() { + const blockId = pageId // Blocks can be appended to other blocks *or* pages. Therefore, a page ID can be used for the block_id parameter + const linkedTextResponse = await notion.blocks.children.append({ + block_id: blockId, + children: [ + { + heading_3: { + rich_text: [ + { + text: { + content: "Lacinato kale", + }, + }, + ], + }, + }, + { + paragraph: { + rich_text: [ + { + text: { + content: + "Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", + link: { + url: "https://en.wikipedia.org/wiki/Lacinato_kale", + }, + }, + }, + ], + }, + }, + ], + }) + console.log(linkedTextResponse) +} + +main() diff --git a/examples/intro-to-notion-api/basic/3-styled-block-text.js b/examples/intro-to-notion-api/basic/3-styled-block-text.js new file mode 100644 index 00000000..b4b0b3ad --- /dev/null +++ b/examples/intro-to-notion-api/basic/3-styled-block-text.js @@ -0,0 +1,58 @@ +import { Client } from "@notionhq/client" +import { config } from "dotenv" + +config() + +const pageId = process.env.NOTION_PAGE_ID +const apiKey = process.env.NOTION_API_KEY + +const notion = new Client({ auth: apiKey }) + +/* +--------------------------------------------------------------------------- +*/ + +async function main() { + const blockId = pageId // Blocks can be appended to other blocks *or* pages. Therefore, a page ID can be used for the block_id parameter + const styledLinkTextResponse = await notion.blocks.children.append({ + block_id: blockId, + children: [ + { + heading_3: { + rich_text: [ + { + text: { + content: "Lacinato kale", + }, + }, + ], + }, + }, + { + paragraph: { + rich_text: [ + { + text: { + content: + "Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", + link: { + url: "https://en.wikipedia.org/wiki/Lacinato_kale", + }, + }, + annotations: { + bold: true, + italic: true, + strikethrough: true, + underline: true, + color: "green", + }, + }, + ], + }, + }, + ], + }) + console.log(styledLinkTextResponse) +} + +main() diff --git a/examples/intro-to-notion-api/intermediate/1-create-a-database.js b/examples/intro-to-notion-api/intermediate/1-create-a-database.js new file mode 100644 index 00000000..e69de29b diff --git a/examples/intro-to-notion-api/intermediate/2-add-page-to-database.js b/examples/intro-to-notion-api/intermediate/2-add-page-to-database.js new file mode 100644 index 00000000..e69de29b diff --git a/examples/intro-to-notion-api/intermediate/3-query-database.js b/examples/intro-to-notion-api/intermediate/3-query-database.js new file mode 100644 index 00000000..e69de29b diff --git a/examples/intro-to-notion-api/intermediate/4-sort-database.js b/examples/intro-to-notion-api/intermediate/4-sort-database.js new file mode 100644 index 00000000..e69de29b diff --git a/examples/intro-to-notion-api/package.json b/examples/intro-to-notion-api/package.json new file mode 100644 index 00000000..ad005d27 --- /dev/null +++ b/examples/intro-to-notion-api/package.json @@ -0,0 +1,24 @@ +{ + "name": "intro-to-notion-api", + "version": "1.0.0", + "description": "Introductory examples of using Notion's public API via the Notion SDK for JavaScript.", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/makenotion/notion-sdk-js.git" + }, + "author": "Jess Mitchell", + "license": "MIT", + "bugs": { + "url": "https://github.com/makenotion/notion-sdk-js/issues" + }, + "dependencies": { + "@notionhq/client": "file:../..", + "dotenv": "^16.3.1" + } +} From 0f718b60a169113a9ad52a9bac6463a4b536b56d Mon Sep 17 00:00:00 2001 From: Jess Mitchell Date: Mon, 14 Aug 2023 16:51:52 -0400 Subject: [PATCH 02/10] update readme --- examples/intro-to-notion-api/README.md | 37 +++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/examples/intro-to-notion-api/README.md b/examples/intro-to-notion-api/README.md index f1f1f24b..d6e5e353 100644 --- a/examples/intro-to-notion-api/README.md +++ b/examples/intro-to-notion-api/README.md @@ -26,7 +26,9 @@ In case you are looking for a specific task, the files are divided as follows: - `/intermediate/3-sort-database.js`: Create a new database with defined properties. - `/advanced/` // todo: add these - not sure what we're including -## Run locally +## Running locally + +### 1. Clone project and install dependencies To use this example on your local machine, clone the repo and move into the cloned repo: @@ -42,6 +44,39 @@ cd /examples/intro-to-notion-api npm install ``` +### 2. Set your environment variables in a `.env` file + +A `.env.example` file has been included and can be renamed `.env`. (or run `cp .env.example .env` to copy the file.) + +Update the environment variables below: + +```zsh +NOTION_API_KEY= +NOTION_PAGE_ID= +``` + +`NOTION_API_KEY`: Create a new integration in the [integrations dashboard](https://www.notion.com/my-integrations) and retrieve the API key from the integration's `Secrets` page. + +`NOTION_PAGE_ID`: Use the ID of any Notion page that you don't mind having content added to. A page specifically for testing is useful! + +The page ID is the 32 character string at the end of any page URL. +![A Notion page URL with the ID highlighted](./assets/page_id.png) + +### 3. Give the integration access to your page + +Your Notion integration will need permission to interact with any Notion page being used. To provide access, do the following: + +1. Go to the page in your workspace. +2. Click the `•••` (more menu) on the top-right corner of the page. +3. Scroll to the bottom of the menu and click `Add connections`. +4. Search for and select your integration in the `Search for connections...` menu. + +Once selected, your integration will have permission to read content from the page. + +**If you are receiving authorization errors, make sure the integration has permission to access the page.** + +### 3. Run individual examples + To run each individual example, use the `node` command with the file's path. For example: From 6eb2850c3277887f57fffd82d0a5f70a7e1ac916 Mon Sep 17 00:00:00 2001 From: Jess Mitchell Date: Thu, 17 Aug 2023 17:00:56 -0400 Subject: [PATCH 03/10] add intermediate example --- .../intermediate/1-create-a-database.js | 49 +++++++++++ .../intermediate/2-add-page-to-database.js | 66 ++++++++++++++ .../intermediate/3-query-database.js | 81 +++++++++++++++++ .../intermediate/4-sort-database.js | 87 +++++++++++++++++++ .../intermediate/sampleData.js | 44 ++++++++++ 5 files changed, 327 insertions(+) create mode 100644 examples/intro-to-notion-api/intermediate/sampleData.js diff --git a/examples/intro-to-notion-api/intermediate/1-create-a-database.js b/examples/intro-to-notion-api/intermediate/1-create-a-database.js index e69de29b..c50328ec 100644 --- a/examples/intro-to-notion-api/intermediate/1-create-a-database.js +++ b/examples/intro-to-notion-api/intermediate/1-create-a-database.js @@ -0,0 +1,49 @@ +import { Client } from "@notionhq/client" +import { config } from "dotenv" + +config() + +const pageId = process.env.NOTION_PAGE_ID +const apiKey = process.env.NOTION_API_KEY + +const notion = new Client({ auth: apiKey }) + +/* +--------------------------------------------------------------------------- +*/ + +async function main() { + const newDatabase = await notion.databases.create({ + parent: { + type: "page_id", + page_id: pageId, + }, + title: [ + { + type: "text", + text: { + content: "New database name", + }, + }, + ], + properties: { + "Grocery item": { + type: "title", + title: {}, + }, + Price: { + type: "number", + number: { + format: "dollar", + }, + }, + "Last ordered": { + type: "date", + date: {}, + }, + }, + }) + console.log(newDatabase) +} + +main() diff --git a/examples/intro-to-notion-api/intermediate/2-add-page-to-database.js b/examples/intro-to-notion-api/intermediate/2-add-page-to-database.js index e69de29b..3fd9a7e0 100644 --- a/examples/intro-to-notion-api/intermediate/2-add-page-to-database.js +++ b/examples/intro-to-notion-api/intermediate/2-add-page-to-database.js @@ -0,0 +1,66 @@ +import { Client } from "@notionhq/client" +import { config } from "dotenv" +import { propertiesForNewPages } from "./sampleData.js" + +config() + +const pageId = process.env.NOTION_PAGE_ID +const apiKey = process.env.NOTION_API_KEY + +const notion = new Client({ auth: apiKey }) + +/* +--------------------------------------------------------------------------- +*/ + +async function addNotionPageToDatabase(databaseId, pageProperties) { + const newPage = await notion.pages.create({ + parent: { + database_id: databaseId, + }, + properties: pageProperties, + }) + console.log(newPage) +} + +async function main() { + const newDatabase = await notion.databases.create({ + parent: { + type: "page_id", + page_id: pageId, + }, + title: [ + { + type: "text", + text: { + content: "Grocery list", + }, + }, + ], + properties: { + "Grocery item": { + type: "title", + title: {}, + }, + Price: { + type: "number", + number: { + format: "dollar", + }, + }, + "Last ordered": { + type: "date", + date: {}, + }, + }, + }) + console.log(newDatabase) + const databaseId = newDatabase.id + if (!databaseId) return + + for (let i = 0; i < propertiesForNewPages.length; i++) { + addNotionPageToDatabase(databaseId, propertiesForNewPages[i]) + } +} + +main() diff --git a/examples/intro-to-notion-api/intermediate/3-query-database.js b/examples/intro-to-notion-api/intermediate/3-query-database.js index e69de29b..15d16b10 100644 --- a/examples/intro-to-notion-api/intermediate/3-query-database.js +++ b/examples/intro-to-notion-api/intermediate/3-query-database.js @@ -0,0 +1,81 @@ +import { Client } from "@notionhq/client" +import { config } from "dotenv" +import { propertiesForNewPages } from "./sampleData.js" + +config() + +const pageId = process.env.NOTION_PAGE_ID +const apiKey = process.env.NOTION_API_KEY + +const notion = new Client({ auth: apiKey }) + +/* +--------------------------------------------------------------------------- +*/ + +async function addNotionPageToDatabase(databaseId, pageProperties) { + await notion.pages.create({ + parent: { + database_id: databaseId, + }, + properties: pageProperties, + }) +} + +async function queryDatabase(databaseId) { + const lastOrderedIn2023 = await notion.databases.query({ + database_id: databaseId, + filter: { + property: "Last ordered", + date: { + after: "2022-12-31", + }, + }, + }) + console.log(lastOrderedIn2023) +} + +async function main() { + const newDatabase = await notion.databases.create({ + parent: { + type: "page_id", + page_id: pageId, + }, + title: [ + { + type: "text", + text: { + content: "Grocery list", + }, + }, + ], + properties: { + "Grocery item": { + type: "title", + title: {}, + }, + Price: { + type: "number", + number: { + format: "dollar", + }, + }, + "Last ordered": { + type: "date", + date: {}, + }, + }, + }) + console.log(newDatabase.url) + + const databaseId = newDatabase.id + if (!databaseId) return + + for (let i = 0; i < propertiesForNewPages.length; i++) { + addNotionPageToDatabase(databaseId, propertiesForNewPages[i]) + } + + queryDatabase(databaseId) +} + +main() diff --git a/examples/intro-to-notion-api/intermediate/4-sort-database.js b/examples/intro-to-notion-api/intermediate/4-sort-database.js index e69de29b..1f9623bb 100644 --- a/examples/intro-to-notion-api/intermediate/4-sort-database.js +++ b/examples/intro-to-notion-api/intermediate/4-sort-database.js @@ -0,0 +1,87 @@ +import { Client } from "@notionhq/client" +import { config } from "dotenv" +import { propertiesForNewPages } from "./sampleData.js" + +config() + +const pageId = process.env.NOTION_PAGE_ID +const apiKey = process.env.NOTION_API_KEY + +const notion = new Client({ auth: apiKey }) + +/* +--------------------------------------------------------------------------- +*/ + +async function addNotionPageToDatabase(databaseId, pageProperties) { + await notion.pages.create({ + parent: { + database_id: databaseId, + }, + properties: pageProperties, + }) +} + +async function queryAndSortDatabase(databaseId) { + const lastOrderedIn2023Alphabetical = await notion.databases.query({ + database_id: databaseId, + filter: { + property: "Last ordered", + date: { + after: "2022-12-31", + }, + }, + sorts: [ + { + property: "Grocery item", + direction: "ascending", + }, + ], + }) + console.log(lastOrderedIn2023Alphabetical) +} + +async function main() { + const newDatabase = await notion.databases.create({ + parent: { + type: "page_id", + page_id: pageId, + }, + title: [ + { + type: "text", + text: { + content: "Grocery list", + }, + }, + ], + properties: { + "Grocery item": { + type: "title", + title: {}, + }, + Price: { + type: "number", + number: { + format: "dollar", + }, + }, + "Last ordered": { + type: "date", + date: {}, + }, + }, + }) + console.log(newDatabase.url) + + const databaseId = newDatabase.id + if (!databaseId) return + + for (let i = 0; i < propertiesForNewPages.length; i++) { + addNotionPageToDatabase(databaseId, propertiesForNewPages[i]) + } + + queryAndSortDatabase(databaseId) +} + +main() diff --git a/examples/intro-to-notion-api/intermediate/sampleData.js b/examples/intro-to-notion-api/intermediate/sampleData.js new file mode 100644 index 00000000..4d03353c --- /dev/null +++ b/examples/intro-to-notion-api/intermediate/sampleData.js @@ -0,0 +1,44 @@ +export const propertiesForNewPages = [ + { + "Grocery item": { + type: "title", + title: [{ type: "text", text: { content: "Tomatoes" } }], + }, + Price: { + type: "number", + number: 1.49, + }, + "Last ordered": { + type: "date", + date: { start: "2023-05-11" }, + }, + }, + { + "Grocery item": { + type: "title", + title: [{ type: "text", text: { content: "Lettuce" } }], + }, + Price: { + type: "number", + number: 3.99, + }, + "Last ordered": { + type: "date", + date: { start: "2023-05-04" }, + }, + }, + { + "Grocery item": { + type: "title", + title: [{ type: "text", text: { content: "Oranges" } }], + }, + Price: { + type: "number", + number: 0.99, + }, + "Last ordered": { + type: "date", + date: { start: "2022-04-29" }, + }, + }, +] From 867f8da1925095ed48affbbe9ff7c6eb09bbc21a Mon Sep 17 00:00:00 2001 From: Jess Mitchell Date: Mon, 21 Aug 2023 16:08:57 -0400 Subject: [PATCH 04/10] add more comments and resources to each example --- examples/intro-to-notion-api/README.md | 29 ++++++++++--------- .../intro-to-notion-api/basic/1-new-block.js | 11 ++++++- .../basic/2-add-linked-block.js | 13 ++++++++- .../basic/3-styled-block-text.js | 12 ++++++++ .../intermediate/1-create-a-database.js | 10 +++++++ .../intermediate/2-add-page-to-database.js | 19 ++++++++++-- .../intermediate/3-query-database.js | 23 +++++++++++++-- .../intermediate/4-sort-database.js | 25 ++++++++++++++-- 8 files changed, 120 insertions(+), 22 deletions(-) diff --git a/examples/intro-to-notion-api/README.md b/examples/intro-to-notion-api/README.md index d6e5e353..912c350d 100644 --- a/examples/intro-to-notion-api/README.md +++ b/examples/intro-to-notion-api/README.md @@ -12,32 +12,35 @@ The sample code is split into three sections: If you are new to Notion's SDK for JavaScript, start with the code samples in the `/basic` directory to get more familiar to basic concepts. -The files in each directory will build on each other to increase in complexity. For example, in `/intermediate`, first you will see how to create a database, then how to create a database and add a page to it, and finally create a database, add a page, and query the database. +The files in each directory will build on each other to increase in complexity. For example, in `/intermediate`, first you will see how to create a database, then how to create a database and add a page to it, and finally create a database, add a page, and query/sort the database. + +The `/advanced` section contains standalone examples and do not build on each other. ## Table of contents -In case you are looking for a specific task, the files are divided as follows: +In case you are looking for example code of a specific task, the files are divided as follows: -- `/basic/1-new-block.js`: Create a new block that will be appended to a Notion page. -- `/basic/2-styled-block-text.js`: Update a block's text styles after creating it. +- `/basic/1-new-block.js`: Create a new block that will be appended to an existing Notion page. +- `/basic/2-add-linked-block.js`: Add a link to the text of a new block. +- `/basic/3-styled-block-text.js`: Include styles for a new block's text. - `/intermediate/1-create-a-database.js`: Create a new database with defined properties. -- `/intermediate/2-add-page-to-database.js`: Add a new page to a newly-created database. -- `/intermediate/3-query-database.js`: Create a new database with defined properties. -- `/intermediate/3-sort-database.js`: Create a new database with defined properties. -- `/advanced/` // todo: add these - not sure what we're including +- `/intermediate/2-add-page-to-database.js`: Add new pages to a newly-created database. +- `/intermediate/3-query-database.js`: Create a new database with defined properties, add pages to it, and filter the database entries (pages). +- `/intermediate/4-sort-database.js`: Create a new database with defined properties, add pages to it, and filter/sort the database entries (pages). +- `/advanced/` // todo: these have not been added yet ## Running locally ### 1. Clone project and install dependencies -To use this example on your local machine, clone the repo and move into the cloned repo: +To use this example on your machine, clone the repo and move into your local copy: ```zsh git clone https://github.com/makenotion/notion-sdk-js.git cd /notion-sdk-js ``` -Next, move into this example in the `/examples` directory and install its dependencies: +Next, move into this example in the `/examples` directory, and install its dependencies: ```zsh cd /examples/intro-to-notion-api @@ -46,7 +49,7 @@ npm install ### 2. Set your environment variables in a `.env` file -A `.env.example` file has been included and can be renamed `.env`. (or run `cp .env.example .env` to copy the file.) +A `.env.example` file has been included and can be renamed `.env` (or you can run `cp .env.example .env` to copy the file). Update the environment variables below: @@ -57,14 +60,14 @@ NOTION_PAGE_ID= `NOTION_API_KEY`: Create a new integration in the [integrations dashboard](https://www.notion.com/my-integrations) and retrieve the API key from the integration's `Secrets` page. -`NOTION_PAGE_ID`: Use the ID of any Notion page that you don't mind having content added to. A page specifically for testing is useful! +`NOTION_PAGE_ID`: Use the ID of any Notion page that you don't mind having content added to. A page specifically for testing is recommended. The page ID is the 32 character string at the end of any page URL. ![A Notion page URL with the ID highlighted](./assets/page_id.png) ### 3. Give the integration access to your page -Your Notion integration will need permission to interact with any Notion page being used. To provide access, do the following: +Your Notion integration will need permission to interact with the Notion page being used for your `NOTION_PAGE_ID` variable. To provide access, do the following: 1. Go to the page in your workspace. 2. Click the `•••` (more menu) on the top-right corner of the page. diff --git a/examples/intro-to-notion-api/basic/1-new-block.js b/examples/intro-to-notion-api/basic/1-new-block.js index c1d74132..a245215d 100644 --- a/examples/intro-to-notion-api/basic/1-new-block.js +++ b/examples/intro-to-notion-api/basic/1-new-block.js @@ -12,17 +12,24 @@ const notion = new Client({ auth: apiKey }) --------------------------------------------------------------------------- */ +/** + * Resources: + * - Appending block children endpoint (notion.blocks.children.append(): https://developers.notion.com/reference/patch-block-children) + * - Working with page content guide: https://developers.notion.com/docs/working-with-page-content + */ + async function main() { const blockId = pageId // Blocks can be appended to other blocks *or* pages. Therefore, a page ID can be used for the block_id parameter const newHeadingResponse = await notion.blocks.children.append({ block_id: blockId, + // Pass an array of blocks to append to the page: https://developers.notion.com/reference/block#block-type-objects children: [ { heading_2: { rich_text: [ { text: { - content: "Types of kale", + content: "Types of kale", // This is the text that will be displayed in Notion }, }, ], @@ -30,6 +37,8 @@ async function main() { }, ], }) + + // Print the new block(s) response console.log(newHeadingResponse) } diff --git a/examples/intro-to-notion-api/basic/2-add-linked-block.js b/examples/intro-to-notion-api/basic/2-add-linked-block.js index d481b786..dcb37659 100644 --- a/examples/intro-to-notion-api/basic/2-add-linked-block.js +++ b/examples/intro-to-notion-api/basic/2-add-linked-block.js @@ -12,17 +12,25 @@ const notion = new Client({ auth: apiKey }) --------------------------------------------------------------------------- */ +/** + * Resources: + * - Appending block children endpoint (notion.blocks.children.append(): https://developers.notion.com/reference/patch-block-children) + * - Rich text options: https://developers.notion.com/reference/rich-text + * - Working with page content guide: https://developers.notion.com/docs/working-with-page-content + */ + async function main() { const blockId = pageId // Blocks can be appended to other blocks *or* pages. Therefore, a page ID can be used for the block_id parameter const linkedTextResponse = await notion.blocks.children.append({ block_id: blockId, + // Pass an array of blocks to append to the page: https://developers.notion.com/reference/block#block-type-objects children: [ { heading_3: { rich_text: [ { text: { - content: "Lacinato kale", + content: "Lacinato kale", // This is the text that will be displayed in Notion }, }, ], @@ -36,6 +44,7 @@ async function main() { content: "Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", link: { + // Include a url to make the paragraph a link in Notion url: "https://en.wikipedia.org/wiki/Lacinato_kale", }, }, @@ -45,6 +54,8 @@ async function main() { }, ], }) + + // Print the new block(s) response console.log(linkedTextResponse) } diff --git a/examples/intro-to-notion-api/basic/3-styled-block-text.js b/examples/intro-to-notion-api/basic/3-styled-block-text.js index b4b0b3ad..764048e5 100644 --- a/examples/intro-to-notion-api/basic/3-styled-block-text.js +++ b/examples/intro-to-notion-api/basic/3-styled-block-text.js @@ -12,6 +12,13 @@ const notion = new Client({ auth: apiKey }) --------------------------------------------------------------------------- */ +/** + * Resources: + * - Appending block children endpoint (notion.blocks.children.append(): https://developers.notion.com/reference/patch-block-children) + * - Rich text options: https://developers.notion.com/reference/rich-text + * - Working with page content guide: https://developers.notion.com/docs/working-with-page-content + */ + async function main() { const blockId = pageId // Blocks can be appended to other blocks *or* pages. Therefore, a page ID can be used for the block_id parameter const styledLinkTextResponse = await notion.blocks.children.append({ @@ -33,13 +40,16 @@ async function main() { rich_text: [ { text: { + // Paragraph text content: "Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", link: { + // Paragraph link url: "https://en.wikipedia.org/wiki/Lacinato_kale", }, }, annotations: { + // Paragraph styles bold: true, italic: true, strikethrough: true, @@ -52,6 +62,8 @@ async function main() { }, ], }) + + // Print the new block(s) response console.log(styledLinkTextResponse) } diff --git a/examples/intro-to-notion-api/intermediate/1-create-a-database.js b/examples/intro-to-notion-api/intermediate/1-create-a-database.js index c50328ec..589a403b 100644 --- a/examples/intro-to-notion-api/intermediate/1-create-a-database.js +++ b/examples/intro-to-notion-api/intermediate/1-create-a-database.js @@ -12,7 +12,14 @@ const notion = new Client({ auth: apiKey }) --------------------------------------------------------------------------- */ +/** + * Resources: + * - Create a database endpoint (notion.databases.create(): https://developers.notion.com/reference/create-a-database) + * - Working with databases guide: https://developers.notion.com/docs/working-with-databases + */ + async function main() { + // Create a new database const newDatabase = await notion.databases.create({ parent: { type: "page_id", @@ -27,6 +34,7 @@ async function main() { }, ], properties: { + // These properties represent columns in the database (i.e. its schema) "Grocery item": { type: "title", title: {}, @@ -43,6 +51,8 @@ async function main() { }, }, }) + + // Print the new database response console.log(newDatabase) } diff --git a/examples/intro-to-notion-api/intermediate/2-add-page-to-database.js b/examples/intro-to-notion-api/intermediate/2-add-page-to-database.js index 3fd9a7e0..5d1ab132 100644 --- a/examples/intro-to-notion-api/intermediate/2-add-page-to-database.js +++ b/examples/intro-to-notion-api/intermediate/2-add-page-to-database.js @@ -13,6 +13,13 @@ const notion = new Client({ auth: apiKey }) --------------------------------------------------------------------------- */ +/** + * Resources: + * - Create a database endpoint (notion.databases.create(): https://developers.notion.com/reference/create-a-database) + * - Create a page endpoint (notion.pages.create(): https://developers.notion.com/reference/post-page) + * - Working with databases guide: https://developers.notion.com/docs/working-with-databases + */ + async function addNotionPageToDatabase(databaseId, pageProperties) { const newPage = await notion.pages.create({ parent: { @@ -24,6 +31,7 @@ async function addNotionPageToDatabase(databaseId, pageProperties) { } async function main() { + // Create a new database const newDatabase = await notion.databases.create({ parent: { type: "page_id", @@ -38,6 +46,7 @@ async function main() { }, ], properties: { + // These properties represent columns in the database (i.e. its schema) "Grocery item": { type: "title", title: {}, @@ -54,12 +63,18 @@ async function main() { }, }, }) - console.log(newDatabase) + + // Print the new database's URL. Visit the URL in your browser to see the pages that get created in the next step. + console.log(newDatabase.url) + const databaseId = newDatabase.id + // If there is no ID (if there's an error), return. if (!databaseId) return + console.log("Adding new pages...") for (let i = 0; i < propertiesForNewPages.length; i++) { - addNotionPageToDatabase(databaseId, propertiesForNewPages[i]) + // Add a few new pages to the database that was just created + await addNotionPageToDatabase(databaseId, propertiesForNewPages[i]) } } diff --git a/examples/intro-to-notion-api/intermediate/3-query-database.js b/examples/intro-to-notion-api/intermediate/3-query-database.js index 15d16b10..6d3cd76b 100644 --- a/examples/intro-to-notion-api/intermediate/3-query-database.js +++ b/examples/intro-to-notion-api/intermediate/3-query-database.js @@ -13,16 +13,26 @@ const notion = new Client({ auth: apiKey }) --------------------------------------------------------------------------- */ +/** + * Resources: + * - Create a database endpoint (notion.databases.create(): https://developers.notion.com/reference/create-a-database) + * - Create a page endpoint (notion.pages.create(): https://developers.notion.com/reference/post-page) + * - Working with databases guide: https://developers.notion.com/docs/working-with-databases + * Query a database: https://developers.notion.com/reference/post-database-query + * Filter database entries: https://developers.notion.com/reference/post-database-query-filter + */ + async function addNotionPageToDatabase(databaseId, pageProperties) { await notion.pages.create({ parent: { database_id: databaseId, }, - properties: pageProperties, + properties: pageProperties, // Note: Page properties must match the schema of the database }) } async function queryDatabase(databaseId) { + // This query will filter database entries and return pages that have a "Last ordered" property that is more recent than 2022-12-31. Use multiple filters with the AND/OR options: https://developers.notion.com/reference/post-database-query-filter. const lastOrderedIn2023 = await notion.databases.query({ database_id: databaseId, filter: { @@ -32,10 +42,13 @@ async function queryDatabase(databaseId) { }, }, }) + + // Print filtered results console.log(lastOrderedIn2023) } async function main() { + // Create a new database const newDatabase = await notion.databases.create({ parent: { type: "page_id", @@ -50,6 +63,7 @@ async function main() { }, ], properties: { + // These properties represent columns in the database (i.e. its schema) "Grocery item": { type: "title", title: {}, @@ -66,15 +80,20 @@ async function main() { }, }, }) + // Print the new database's URL. Visit the URL in your browser to see the pages that get created in the next step. console.log(newDatabase.url) const databaseId = newDatabase.id + // If there is no ID (if there's an error), return. if (!databaseId) return + console.log("Adding new pages...") for (let i = 0; i < propertiesForNewPages.length; i++) { - addNotionPageToDatabase(databaseId, propertiesForNewPages[i]) + // Add a few new pages to the database that was just created + await addNotionPageToDatabase(databaseId, propertiesForNewPages[i]) } + // After adding pages, query the database entries (pages) queryDatabase(databaseId) } diff --git a/examples/intro-to-notion-api/intermediate/4-sort-database.js b/examples/intro-to-notion-api/intermediate/4-sort-database.js index 1f9623bb..39e63343 100644 --- a/examples/intro-to-notion-api/intermediate/4-sort-database.js +++ b/examples/intro-to-notion-api/intermediate/4-sort-database.js @@ -13,16 +13,27 @@ const notion = new Client({ auth: apiKey }) --------------------------------------------------------------------------- */ +/** + * Resources: + * - Create a database endpoint (notion.databases.create(): https://developers.notion.com/reference/create-a-database) + * - Create a page endpoint (notion.pages.create(): https://developers.notion.com/reference/post-page) + * - Working with databases guide: https://developers.notion.com/docs/working-with-databases + * Query a database: https://developers.notion.com/reference/post-database-query + * Filter database entries: https://developers.notion.com/reference/post-database-query-filter + * Sort database entries: https://developers.notion.com/reference/post-database-query-sort + */ + async function addNotionPageToDatabase(databaseId, pageProperties) { await notion.pages.create({ parent: { database_id: databaseId, }, - properties: pageProperties, + properties: pageProperties, // Note: Page properties must match the schema of the database }) } async function queryAndSortDatabase(databaseId) { + // This query will filter and sort database entries. The returned pages will have a "Last ordered" property that is more recent than 2022-12-31. Any database property can be filtered or sorted. Pass multiple sort objects to the "sorts" array to apply more than one sorting rule. const lastOrderedIn2023Alphabetical = await notion.databases.query({ database_id: databaseId, filter: { @@ -34,14 +45,17 @@ async function queryAndSortDatabase(databaseId) { sorts: [ { property: "Grocery item", - direction: "ascending", + direction: "descending", }, ], }) + + // Print filtered/sorted results console.log(lastOrderedIn2023Alphabetical) } async function main() { + // Create a new database const newDatabase = await notion.databases.create({ parent: { type: "page_id", @@ -56,6 +70,7 @@ async function main() { }, ], properties: { + // These properties represent columns in the database (i.e. its schema) "Grocery item": { type: "title", title: {}, @@ -72,15 +87,19 @@ async function main() { }, }, }) + // Print the new database's URL. Visit the URL in your browser to see the pages that get created in the next step. console.log(newDatabase.url) const databaseId = newDatabase.id if (!databaseId) return + console.log("Adding new pages...") for (let i = 0; i < propertiesForNewPages.length; i++) { - addNotionPageToDatabase(databaseId, propertiesForNewPages[i]) + // Add a few new pages to the database that was just created + await addNotionPageToDatabase(databaseId, propertiesForNewPages[i]) } + // After adding pages, query the database entries (pages) and sort the results queryAndSortDatabase(databaseId) } From 1b9ab2c9c41774d750f1c2b139150a0b4c5375ac Mon Sep 17 00:00:00 2001 From: Jess Mitchell Date: Mon, 21 Aug 2023 16:21:47 -0400 Subject: [PATCH 05/10] add additional resources section --- examples/intro-to-notion-api/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/intro-to-notion-api/README.md b/examples/intro-to-notion-api/README.md index 912c350d..e8b8ba38 100644 --- a/examples/intro-to-notion-api/README.md +++ b/examples/intro-to-notion-api/README.md @@ -87,3 +87,13 @@ For example: ```zsh node /basic/1-new-block.js ``` + +--- + +## Additional resources + +To learn more, read the [public API docs](https://developers.notion.com/) for additional information on using Notion's API. The API docs include a series of [guides](https://developers.notion.com/docs) and the [API reference](https://developers.notion.com/reference/intro), which has a full list of available endpoints. + +To see more examples of what you can build with Notion, see our other sample integrations in the parent `/examples` directory. To learn how to build an internal integration with an interactive frontend, read the [Build your first integration](https://developers.notion.com/docs/create-a-notion-integration) guide. + +To connect with other developers building with Notion, join the [Notion Devs Slack group](https://join.slack.com/t/notiondevs/shared_invite/zt-20b5996xv-DzJdLiympy6jP0GGzu3AMg). From 653867ccaf81ecbd4bc832ab697ebce903e1a5c5 Mon Sep 17 00:00:00 2001 From: Jess Mitchell Date: Thu, 31 Aug 2023 16:21:07 -0400 Subject: [PATCH 06/10] rename some files for consistency, clean up readme, more console logs --- examples/intro-to-notion-api/README.md | 18 ++++++++---------- .../basic/{1-new-block.js => 1-add-block.js} | 0 ...led-block-text.js => 3-add-styled-block.js} | 0 .../intermediate/3-query-database.js | 1 + .../intermediate/4-sort-database.js | 3 +++ 5 files changed, 12 insertions(+), 10 deletions(-) rename examples/intro-to-notion-api/basic/{1-new-block.js => 1-add-block.js} (100%) rename examples/intro-to-notion-api/basic/{3-styled-block-text.js => 3-add-styled-block.js} (100%) diff --git a/examples/intro-to-notion-api/README.md b/examples/intro-to-notion-api/README.md index e8b8ba38..e1bc8ee4 100644 --- a/examples/intro-to-notion-api/README.md +++ b/examples/intro-to-notion-api/README.md @@ -4,30 +4,28 @@ Use this sample code to learn how to make public API requests with varying degrees of difficulty. -The sample code is split into three sections: +The sample code is split into two sections: 1. basic 2. intermediate -3. advanced + +(An `advanced` section will soon be added, as well.) If you are new to Notion's SDK for JavaScript, start with the code samples in the `/basic` directory to get more familiar to basic concepts. The files in each directory will build on each other to increase in complexity. For example, in `/intermediate`, first you will see how to create a database, then how to create a database and add a page to it, and finally create a database, add a page, and query/sort the database. -The `/advanced` section contains standalone examples and do not build on each other. - ## Table of contents In case you are looking for example code of a specific task, the files are divided as follows: -- `/basic/1-new-block.js`: Create a new block that will be appended to an existing Notion page. +- `/basic/1-add-block.js`: Create a new block that will be appended to an existing Notion page. - `/basic/2-add-linked-block.js`: Add a link to the text of a new block. -- `/basic/3-styled-block-text.js`: Include styles for a new block's text. +- `/basic/3-add-styled-block.js`: Include styles for a new block's text. - `/intermediate/1-create-a-database.js`: Create a new database with defined properties. - `/intermediate/2-add-page-to-database.js`: Add new pages to a newly-created database. - `/intermediate/3-query-database.js`: Create a new database with defined properties, add pages to it, and filter the database entries (pages). - `/intermediate/4-sort-database.js`: Create a new database with defined properties, add pages to it, and filter/sort the database entries (pages). -- `/advanced/` // todo: these have not been added yet ## Running locally @@ -60,7 +58,7 @@ NOTION_PAGE_ID= `NOTION_API_KEY`: Create a new integration in the [integrations dashboard](https://www.notion.com/my-integrations) and retrieve the API key from the integration's `Secrets` page. -`NOTION_PAGE_ID`: Use the ID of any Notion page that you don't mind having content added to. A page specifically for testing is recommended. +`NOTION_PAGE_ID`: Use the ID of any Notion page that you want to test adding content to. The page ID is the 32 character string at the end of any page URL. ![A Notion page URL with the ID highlighted](./assets/page_id.png) @@ -85,14 +83,14 @@ To run each individual example, use the `node` command with the file's path. For example: ```zsh -node /basic/1-new-block.js +node /basic/1-add-block.js ``` --- ## Additional resources -To learn more, read the [public API docs](https://developers.notion.com/) for additional information on using Notion's API. The API docs include a series of [guides](https://developers.notion.com/docs) and the [API reference](https://developers.notion.com/reference/intro), which has a full list of available endpoints. +To learn more, read the [Public API docs](https://developers.notion.com/) for additional information on using Notion's API. The API docs include a series of [guides](https://developers.notion.com/docs) and the [API reference](https://developers.notion.com/reference/intro), which has a full list of available endpoints. To see more examples of what you can build with Notion, see our other sample integrations in the parent `/examples` directory. To learn how to build an internal integration with an interactive frontend, read the [Build your first integration](https://developers.notion.com/docs/create-a-notion-integration) guide. diff --git a/examples/intro-to-notion-api/basic/1-new-block.js b/examples/intro-to-notion-api/basic/1-add-block.js similarity index 100% rename from examples/intro-to-notion-api/basic/1-new-block.js rename to examples/intro-to-notion-api/basic/1-add-block.js diff --git a/examples/intro-to-notion-api/basic/3-styled-block-text.js b/examples/intro-to-notion-api/basic/3-add-styled-block.js similarity index 100% rename from examples/intro-to-notion-api/basic/3-styled-block-text.js rename to examples/intro-to-notion-api/basic/3-add-styled-block.js diff --git a/examples/intro-to-notion-api/intermediate/3-query-database.js b/examples/intro-to-notion-api/intermediate/3-query-database.js index 6d3cd76b..16d3ae40 100644 --- a/examples/intro-to-notion-api/intermediate/3-query-database.js +++ b/examples/intro-to-notion-api/intermediate/3-query-database.js @@ -44,6 +44,7 @@ async function queryDatabase(databaseId) { }) // Print filtered results + console.log('Pages with the "Last ordered" date after 2022-12-31:') console.log(lastOrderedIn2023) } diff --git a/examples/intro-to-notion-api/intermediate/4-sort-database.js b/examples/intro-to-notion-api/intermediate/4-sort-database.js index 39e63343..bc0ef8c7 100644 --- a/examples/intro-to-notion-api/intermediate/4-sort-database.js +++ b/examples/intro-to-notion-api/intermediate/4-sort-database.js @@ -51,6 +51,9 @@ async function queryAndSortDatabase(databaseId) { }) // Print filtered/sorted results + console.log( + 'Pages with the "Last ordered" date after 2022-12-31 in descending order:' + ) console.log(lastOrderedIn2023Alphabetical) } From 04f1eaecd3845eeb6c517687bdfc995d7e75246f Mon Sep 17 00:00:00 2001 From: Jess Mitchell Date: Thu, 31 Aug 2023 16:24:04 -0400 Subject: [PATCH 07/10] make linter happy --- examples/intro-to-notion-api/README.md | 2 +- examples/intro-to-notion-api/basic/2-add-linked-block.js | 6 +++--- examples/intro-to-notion-api/basic/3-add-styled-block.js | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/intro-to-notion-api/README.md b/examples/intro-to-notion-api/README.md index e1bc8ee4..2b929478 100644 --- a/examples/intro-to-notion-api/README.md +++ b/examples/intro-to-notion-api/README.md @@ -94,4 +94,4 @@ To learn more, read the [Public API docs](https://developers.notion.com/) for ad To see more examples of what you can build with Notion, see our other sample integrations in the parent `/examples` directory. To learn how to build an internal integration with an interactive frontend, read the [Build your first integration](https://developers.notion.com/docs/create-a-notion-integration) guide. -To connect with other developers building with Notion, join the [Notion Devs Slack group](https://join.slack.com/t/notiondevs/shared_invite/zt-20b5996xv-DzJdLiympy6jP0GGzu3AMg). +To connect with other developers building with Notion, join the [Notion Developers Slack group](https://join.slack.com/t/notiondevs/shared_invite/zt-20b5996xv-DzJdLiympy6jP0GGzu3AMg). diff --git a/examples/intro-to-notion-api/basic/2-add-linked-block.js b/examples/intro-to-notion-api/basic/2-add-linked-block.js index dcb37659..a3afa581 100644 --- a/examples/intro-to-notion-api/basic/2-add-linked-block.js +++ b/examples/intro-to-notion-api/basic/2-add-linked-block.js @@ -30,7 +30,7 @@ async function main() { rich_text: [ { text: { - content: "Lacinato kale", // This is the text that will be displayed in Notion + content: "Tuscan kale", // This is the text that will be displayed in Notion }, }, ], @@ -42,10 +42,10 @@ async function main() { { text: { content: - "Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", + "Tuscan kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", link: { // Include a url to make the paragraph a link in Notion - url: "https://en.wikipedia.org/wiki/Lacinato_kale", + url: "https://en.wikipedia.org/wiki/Tuscan _kale", }, }, }, diff --git a/examples/intro-to-notion-api/basic/3-add-styled-block.js b/examples/intro-to-notion-api/basic/3-add-styled-block.js index 764048e5..8de9e737 100644 --- a/examples/intro-to-notion-api/basic/3-add-styled-block.js +++ b/examples/intro-to-notion-api/basic/3-add-styled-block.js @@ -29,7 +29,7 @@ async function main() { rich_text: [ { text: { - content: "Lacinato kale", + content: "Tuscan kale", }, }, ], @@ -42,10 +42,10 @@ async function main() { text: { // Paragraph text content: - "Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", + "Tuscan kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", link: { // Paragraph link - url: "https://en.wikipedia.org/wiki/Lacinato_kale", + url: "https://en.wikipedia.org/wiki/Tuscan _kale", }, }, annotations: { From 0f599b9c62e21b3747d4ce6a7c79cda0f1f405bc Mon Sep 17 00:00:00 2001 From: Jess Mitchell Date: Thu, 31 Aug 2023 16:41:16 -0400 Subject: [PATCH 08/10] readme updates --- examples/intro-to-notion-api/README.md | 20 +++++++++--------- .../intro-to-notion-api/assets/page_id.png | Bin 0 -> 39795 bytes 2 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 examples/intro-to-notion-api/assets/page_id.png diff --git a/examples/intro-to-notion-api/README.md b/examples/intro-to-notion-api/README.md index 2b929478..12c0dd37 100644 --- a/examples/intro-to-notion-api/README.md +++ b/examples/intro-to-notion-api/README.md @@ -1,13 +1,13 @@ # Introduction to using Notion's SDK for JavaScript -## Learn how to make public API requests +## Learn how to make Public API requests -Use this sample code to learn how to make public API requests with varying degrees of difficulty. +Use this sample code to learn how to make Public API requests with varying degrees of difficulty. The sample code is split into two sections: -1. basic -2. intermediate +1. `basic` +2. `intermediate` (An `advanced` section will soon be added, as well.) @@ -19,13 +19,13 @@ The files in each directory will build on each other to increase in complexity. In case you are looking for example code of a specific task, the files are divided as follows: -- `/basic/1-add-block.js`: Create a new block that will be appended to an existing Notion page. -- `/basic/2-add-linked-block.js`: Add a link to the text of a new block. -- `/basic/3-add-styled-block.js`: Include styles for a new block's text. +- `/basic/1-add-block.js`: Create a new block and append it to an existing Notion page. +- `/basic/2-add-linked-block.js`: Create and append new blocks, and a link to the text of a new block. +- `/basic/3-add-styled-block.js`: Create and append new blocks, and apply text styles to them. - `/intermediate/1-create-a-database.js`: Create a new database with defined properties. -- `/intermediate/2-add-page-to-database.js`: Add new pages to a newly-created database. -- `/intermediate/3-query-database.js`: Create a new database with defined properties, add pages to it, and filter the database entries (pages). -- `/intermediate/4-sort-database.js`: Create a new database with defined properties, add pages to it, and filter/sort the database entries (pages). +- `/intermediate/2-add-page-to-database.js`: Create a new database and add new pages to it. +- `/intermediate/3-query-database.js`: Create a new database, add pages to it, and filter the database entries (pages). +- `/intermediate/4-sort-database.js`: Create a new database, add pages to it, and filter/sort the database entries (pages). ## Running locally diff --git a/examples/intro-to-notion-api/assets/page_id.png b/examples/intro-to-notion-api/assets/page_id.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e837b64995dfa5bd81d93dfeeb9d2ccbcf4416 GIT binary patch literal 39795 zcmeFZg;!fm*FH>zLXlD^QlLO_iUgOU#i0}{8X!>INztI8rMMO-ZUu@HDDF_KxI==c zXmGcnU+(99Y`wqr{srHC)|$*@X7=pNoPGA*bIm>p(@;|+#G}H)!ong{R+4*{by_YtN>0oC7&g+(A?D=Vv^EGzp`!v$<*>tKn6r4*K+hoi66N1kaI_x0=Oed4bq z-p_vMy`ryHN?@PHRsN)5M(~hKjDfx0L-QVWBYVz<0Tz(M%$itxr%_)+11=BR=}#ja zbvHpT`XcAi`%>1ouIuwDKKoeTq2V0lsP9x*tKmn?71^H$5Bpxd8|Q!X(Bcg?`3I(? zBvz~LE;%gy;MumMI$f4z+lL!`*uRRa2!aj>cW%UdMUGQLelBsj{;e29S z8OldRSU%VN&h`18OtV}tKWY8j;0e-;PxCC2iGQU%sNt(F{J|AwfTJ7|rom^ZkJh(Y zn-@rCVMWo^P7+c?$s5w`o7B(a zu9gIKSiM5y8->l64{5_g&>}Q?a!9%_de@|3L|Cht{U+mj==hsiKqD-Y(Wcrjs#QCN|IK$ez zUYb4U4Yc{Py#lQ#qPODeE{n2I;Ergud)&29HPYC@J(Y z_TIDDrc*4QDQ+Mv>26^F+jxMDFGzX4`FKOg<- zQZtLv=kPEJ4$(tALvK+Xk#oebQg7kjErB=s`uS2&`rFgn7r?P3?qqr&#Rq5Fhws98 z82PjM0!$v>i)UPZ9cd;iCfbDc@~V~1*aZCiX#Y`1{Yex@Bhe@D(VstmD!@h$=i5Sj z{+#V!{RU3me>xr|1II$Gd^RPE&u@+2ZeQ)GKNmHUY<@&!)DPdO<7D+>; zqZtZfBb0DlsJ%i@7|LT~*n;0{I!->VkyFggWWy&^Tp3fgc_d26B^NQaw(+Q%Y9Rui zTQD|Y!#W$(`UZ#RQ;`|L;KQmOab6+vsJsuG$q&;a63o{01$9FN+flxR+Z~rbiA0DC zR^H9imi^%ozlU0yIB2-wYrc<+LacCI2wu}K#`rUj;y!vP79jjt_PKiR%Xh5bp7uW$ zd#s3Sy=1(_(#%W}Mvy}`_F%8u!i?OR+?mq(nX}X(X~ma|WRW)vu_sC%OeXII!c_WM z6TS+?oyDoemBlqG@9SvmMCzpL$Y{UUmSdM^Ut{;tRx32p@yb66E0wN&=@XyZ=X><- z2=C~L%QG}yL)vv%j&eoL#rx$~z;D>!2)~K;1N$ZVsdaR8v~;+qoQq|q(8bi+M1{s0 zeubBxi{)$bDvO>Kz29=#0&Kn7a@?Y(in3D1|DHE`WIJFhSj}IJQ+;mdCWs>#O=aSk zX^>~oGOJUQv}NIr@1A&RaVm4_aw@x}H+dz{OO;6FKv?$MDC%ugE|sw0BZ19SwbZfH zhSULpa~tEyoiPSmpdGgTVNG~Vt$oIr_q(1AD>tDGMH3~Yw3Ny|oW;)2*0s8-dZ7B; zw$Ao^+h((Vi)m|cv}p2m*+loR=ZOSQ7(*%ooWDAMIdl$O!iD3uhvqSEDHzclszH7@ zeJXoXrwwUyD%ew$$T$9JT)W8L@~GwNvc45|D{`}WnRYs|bsjZIyU8CXTBZ4RbS;FpMYQmA{XOz5=_aiGK;ZzwsTY~x2SCsfs2&yar=wqJ|iUtkV#w z$cmSSo(2{MrFA0U!{PCMzCM=<%P*EO31wtG#iPaWtxUn8S)_NWd(Ejkbxu@)YV8n9 znup;ed`M`bcKj@y#t!AgT0Lih;0@>LxBq6NeOj1yrtOpH_t_72Ba0I(8z>tq`=xVW zY&};?p`6MOdZMQ&-1DM`CK{4ao&H;t?6u(Q7LQu@_1Ai$CXnog!1_T~TQ{#YI~4oJ zg&psKs6Fz{+G*I#ZbVZ^Q&-Dy3!-zLaVoceCBLB7IugYVb%0`fUZRIV#feaY1lTkY1ov_|K@Xasu)>vF3~jxy6XeP!f4T zxi26Z%7Zm(uF7p%m1=BMXsFe+8t>v?>mMEe~6Jmeic2Vin(e%Ph z5#9=xL(qGT@vR?ahq*l?l>V=QQo!W-WSO_h?`Bf?c<4Pl8Xqq_TVP3i*UZ~zHy)`> z!Md$JoZ{;neo4CbO|~d-^2ek^QC7p)yxra#DpnXfEURZ7hHCkPbAUMV!EOzh3b5X6 z-7J~#;q&E(Tbx*3S|?hcJ)Y^nTPi92S;__6ugtB2SQ4!>t?i8H^r;R>u#b~iMi}H% zsb=uj$U3kBh#{)SnYB&^ZA?a${6u|e-w?^=g#N3BdGK-h@eph%b^`W(0jrvnfUIk< zjl%Z3xfB&^Ne+Tn*Iwk35yB;2wS7C-RdmCqLo-4YDQQA=UYRq^%U%n|vZ#IIH^8qg zf9e=|a;D_{x!xH}Ydh$Rw_P0OjLO$A+cC$*rA7FWgMk6u!~k2vtxC6*@$$UuaTUvG z%Qefaq{BqeW#482p%fuN-DI)0!>@Zip(`OLL0A`EKHFm8>b|tqW6yw?EVnG<0$m{* zUu^>tn-al5bs#qgSwn9oyP|L$#UTtW>n+_VB`BRYvDB!k-dbR}%`ZuNAcSz_oqu1u zwxYWPH=L8Ho6?;rzhKyoZL9Tp^(ax;PSV+ zF3s<0K^N`J{sQ6irQypLv$8;rJF;IN zQXdA8u+vNAn*6N2LJf7p#yH-6fkq7(hgzayMKr@8)t1`hQMSp13<3+F>kI#JD1 z%MOL4B-VETpwoS$ltoIfACEZmLG7bnjRJtb`&d{Zwpb7U*+&hN z|8;%Eq`zqXCw~wZjD>^wMuJJ6-|zpcH@3m|2mdPHG<)laj?Wa zMKMK3OE=S(o{kPquA-h24FBjMiYfn9&CT%gA6?w+B^dNoHD1bsT`XS;0eApB43c;+ zU%nJ~v9J<-FQ@QNa?Cdg1{*iGkD}b%5C{YS;Rk?Sthsq#zkbcl!^h3X$A#&^Q#5|DTrsaQrVy{r^z% z@(c6)H|c*h{clnoS4$UJup@@2o8*7)*FTB>yYZid;@p2t{lAvtf7baQwU~vL#1rTK z_f3<;yM)%f#@xpjwsPv)m>eTz|G1JdpKO@)SB^h0PSXe_KZSjuwJ+Mf4zGH}v$ z1ZP8X%d+;^&lZ0z`hY_N!o$N0*>t^$V;3LZBYya5JT26$JDiOnC+FqMP|#S7)=qfK z?p7lA9slY(r}cR;$of3xs9#6SYp%XNKQ*;JDez+HsR=c~z57o;VLg0_br1Iq*8eW{ ztA5}Lgu7HR(*GYFUSfR?#ggG5`@aWy^Y%V2?A5)v7yo)-bCZ~OVT{rua0{%t@1wx9pUHt%o$;s0O$!*`d* z*T>tI2|hBzkN&;uzkTx%KG!@;S6J;|mcvke+fc^Z_UPYU#r5Xnm({nM+`Ljx|5^8$ z^x;zjtzRlBq}hVZZ{lSCvxC9YSTfsNO_R8=k{Ai=;Qt6L8xCermp6=${{=+c@niVwA@gpvaA8u{ z2Q6Nkc}at!+og`tl9&2bdyU&=k~wFCNa$6R*ZBfuP+jWALTJH_zv_I^C#~)F6dY!G zxt3%yI0wFyc&nB7maOV(&u3O3jper`>%Uk${q%_!7dCnS-@wS%3@jOY4VJ2IbWV>FUYvg6wK{fK+jcbXddw&d z-;G!Dy*^}3Zo6LNcA`+hee*|M;g8fEItIOwOJ-G&QJh)>H`rD`+rD`H^wY1@w|~;W zt+g5B{=Am}bS_RHTzmu{5%@hf$+_)te=znv{e|C2?Fk*Fk?L~Q2?K~=t zlLo7uZS1-|+N&=EgOBF}(3(fBH;+&Ku=3P}jVeU=Senkl7YdfPbk(~?V%b!OjJP>7hv0eegRVGY;}z+Ic-=X4Q~2<#0to@lecT%Wk;b z-*nLy@h$ZBMtpZq+5T-sW#Y=jNE;8G|8)`i>}o$(VY*CAPjC)g2Lt--)>P#el|Bdp z%n2i**1EpeVd#^pk=^q>Z>yf&I)1UepDjTDmQ(g^R(X`yU8iNfR*dA>C2iBL-6If0 zReI#^hDa(oZ$LMhTMtU({!Mqm8Ar>#fCfIT;34fVo|2IECVRim|Mn~meG#u7b#!xk zMK`E+W<2MPva|X^7^kSQ&VGTJTW9m}EzX(YCiU^Q)UBz|g2l5mld+pL4iGR#(0*df z*K(gaC{2+_(9ogP3s@Dpk|bDe0==2yG&!t5UrdZdM$*(GJ*cbVTOh*4m8R*|K)u$g zc|G5giW%Q3)gcd|wkcZ?O=84B1a})>mOt9Ei+!kuodY2yb4^C)XSV0FL3|9K+fOA* z1Vn`UPSfM0X5UZb)8U9Z;Hww++&`v6_JEqfE-QSl@SP4zHMKRCUt&e`8~qs?bnAk}6fvdfIiwJe zy2On`*nXT#)^`$;;Pc~D&g#~qS?cvfv3=fhZZD45cQ>xXe5%yOM#Un+r?HglXRpp# z*JB+~WJ6RbT56*7bEaB_l?~5It7(9B^Ug6TyxXtpIE-(1%l!pmsm4xfQhA9qMKx;8 zZKWK3j|h0nTU(hJXR2St^Vco}Q?F%xzyjClK>$*N8 z%HjlHL`48?7x!I{!lpW9nQNJcqtXOs#Kp~Z!^~$ZdYqb))%0rkeD+!mmk%rV#9@o_ z&M5`+d;k*Gfz*(QEU@wN>7P#iLDjm&r8p~2>U2GXk@nquGd7}|yVcA}LZYYn>~~s) z%?_XV>aUxj_A~!4$0K2KJatGe_bf?46tE7MzeZW3E;IyatCvfaG48xGC>ac~7I(_5 zYttMtY=b&B_Wia(www#}yzr{`%S0H#aw=cG%eYN$xY@hn^CZ|q4D7US11PW9&CDCf z5OW@zwyl_!$enYfH8;Qa#-~WXpxKLF53@xn$41~0T&&{f_7U8#F-zi{nIfGc?AEEx zkfBa)w zw2L2aad0bki*Edp9jxe~&8i8t3`-M?m-_X2LJdZVp4QRaZ@Ht_sY^W#BZhv0@wL)Kaw<^Jbs>xK6h#&HyTF z05qD!jbB{_pX@t6ky?G}uh#%SCR04_6VGa%Y@e>(7F^$jAV*U2L={;gpQp3EZwMrz zFAzWYn(|Sl^27GBt=BK;Rr0pChhUmR`fCH&-B;rEuo>6uLa%a!L~gCEzhy+^MNo6_ z*3X8;MDT4#Hzi7Gw$M`kdf2hN@MH|HjMIDHXnf~w9VK@UVN?4~6@vEALmp;ii^K*u zpL(RXbfIW=loA~4X8I?^wj(|LvvrL<(K-_)$nWowRV1A_AOy$O%fpeV(XENXd3TI* zU2bt%dwYC5B9$^EG*>!l+K!x~w?z7#!)88qvRfUKcCuC8e3KEfQzW3X%b)kNb}N2F z0WzDd-A>-E&gXQlvZ@TGyEvIpf7jCJp7Xxn3}e)@-tMf4m8k93FG2VHbR$8X)O+?K zXM&ZUl~(0`{b9~CwEoMKRbezxvS0>jkLDDqeW2D#S8D9brbbTnj>?;v+VXvWnAhr( z?bt|TqawE}d~hpT^IYya)Wp$<&*vJ1 zUhSF?U$AqI96%*c>pMK&Qsn#@0q9$lZ6>{tO3lKUV25rC3-qGLgzB=AL0_Ne6*y!AM>X7k&jkHwVNcQQ(7Wz<;#YH;8w)`D$kMz)JJk@>DM1hG1V24OwaGs+HAxX|+(hI7j@2hePd zkafDjfMY6amKXelT7YvAFz_~Rv^YB6hc-P?=LAS2WA9a#Akr)9x>0CB|C+jBwnj~0 zLCiQ|_kgORZS*{C?;dar?XC(h38C}W5STR4^%$8^qrEeJy;Pr@`y~2lF9PXnFY31M zmsH(b|Dbk}Z zalAF}9OJ3*n^i`;FC1N~lv_lKj8;?#KVe&1A4yQ8Vcz0#md;@J*{w*MY1mSWrH*9= z&xFAw@D;=Ao+%QBl|`wzu526vVIiP&hXD;6u2sQrb4evT{CkYs;T_mFl2bTSyi+jY z#cLmhg*dXcs0U?&IzpUn+t`q@O3u?AEudfaL|!>T_NmF;WnGb%)gfD#!@i+je)T|# zx}@WyMGM1ecUcYduDDm}`KCvRfmi3cL#4vWCu42wn5-u!ZqLPYJIWbs+NT@bLUssL1Tc}cxS+=QP-?3h24zIvwCz&Z_ zxsS$!l@xj2#TT54iR?9ii%*d)$9GI2g1d?oe+ggP?g)Fe?!%J)LH_2fI#{KyWoGN7 zYs>K>4!p5S>xDYu)RM4~b;!aV)&4{{XR!AP7p*ZH{aIo~Ckae~`QY{WgBXdAdJWgy zTj^w)wWG7TSM*s2J2R;$0>#;t>ObDn)PN{uN}!!VgoYNl zYzw7d{S01Ou!dFG1}j{(8Rj%l9Ror?bB-9-?!7Y703Bo3PSICiS`MEZ6kXQ=2QCfw zl1Xkz(GwC!KV|1fE;|7n%h2Q3k0XO)O*|K0QvzOFEQvUr1QMK+d)F$-oyf9X^j*H+ zdwzW|8z&6=t|NZ=7ICuJ_lzV<3)*P3ofnqdFdp3Vc7UV$Tbao|=S0q!B`^2m3L**7 ziOA<-yu$`gY5?&%r{-N<8T_{rsK#o?j6-o`i`i zVa_Gja=t(~Q4*JMltE2||90*Jb*Z}nQAPBgdl_LhkwCS2i}g5- z-q^S^vHORO8lVR`ZX$ymCKKhwxm4!ghP?m&?8%GKk#{~D?QC@ptwLFz%gz%e*5_<$ zLk0!Ow+ITUYdmd&O5g+Bm(^wWDB3v!SXfGZ;I?D5q9Wov_P^}tk;-I;u1^g(0_+;a z~$!b_wJ-}g_PgXl& ztu(kq$aZ0onKyx}IuRouzepYx0NcLeVIJKf?-4oT+n4@$er>knc~#ua;k3esm@Uxbm$vaiFwL;EIAMr1*U5jj^ z%SAz%FYo3Ve=odXPSCl^5RM588j&%P&9by*B)Zlluk_GqVCV3??M_<1KXkMCG{;>d&vzPSNFnQUmltqE8XmdDDKYIkd8+xzeh{%5SZo$SK<@So}Pl z-#iNfnS0FPF;nxS^FsPTxv*BjB3(jpM8-v7X2!+F0wmn8Db(-%XwNv#ej5eN<$%d; zTyotLJGRRsOO;$t|C)45;bK!0bdD>EfH$+A@%)jMvVlU2o-3gS37AJV;e`sYzlxohXI*+ z$Xde_Q?E>4v&4pc>pB~VEzOJl<{QXWdPS9zVOzR4+@Wfy)(UxZrjq_mBj7UW%%J}J zb`lJ_=?(koJ{FV#nGtmM&{!zJOd=*zueh_gs%fv*&_Oo33zGOZ;-Y7Y7wpP1oXt%f!)89Wr^SG$PTlZUNv;QQEZE zXgugva_hc3SpnMF$~#TaOJR)RB>4reJumT1v%*)yAwl^l4>RJ;`&)%L^^BbXUtsk+G*@ zg!|WRcLQy$zUZm9$G0IWLlh=u)gwE1$smt1D@>fVt3g@%$Jy7;UVt)_5dpB9ZF5HT zI1F;;w8q2SeHS+x&87 z>;|}Us%LI{`P2aq<~8PpxKfkj)kKEVT{Uw>lz~CIQ{Cs1`c#BpZZPQA5ZutwHpFBv z-BpGb`Btk_aIJ?|uO3{y##a#TZgI`8Ime`o73*^Djf6Am@zv8|pMAyFTu_4>a_d$V&*k&`I_X1K`DKvm zRjISI`=9H9)Nc66gYsQdQ2UGZCrSFl)qB{F%8q(UeY8hDRX&m^8EzdUS_L}dH&^l>v8$80nX~Jrgbi#n2nj26a?OMyQWC& zIYX%uWwYktoA&XwvAR#0uR4E|syY;&yC5?`M#PN5#50*DYiIx^pG#?qWR;TZ*bhgp zG*U=y7b~dd=#VulB_hq3c>fGULSOw`pWP2TyJkFA@Ah%0!miMqgLxxl`vra=H0+7U z!At&wV0y|ZHo>2%Lal=_iS?2m^K!@jXF-|ZdD$mi-kKmpU0upw08i#ZJ+mp9GrQ(e&RVr}ZOgvseY0^NC9M6j(teeDIt*%5L~ut|*(|wQrCV}- z=6p3-j{H?^lec8reX40YTjNNh2u5aCHT>y_Sa$SZ`%V94(C=I|%%kXuY87Etln^@! zvgSC1u2s0x>4lk<gQ5M;-FyZE2_V z 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 Date: Mon, 4 Sep 2023 10:33:54 -0400 Subject: [PATCH 09/10] clean up links --- examples/intro-to-notion-api/README.md | 4 ++-- examples/intro-to-notion-api/basic/2-add-linked-block.js | 2 +- examples/intro-to-notion-api/basic/3-add-styled-block.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/intro-to-notion-api/README.md b/examples/intro-to-notion-api/README.md index 12c0dd37..8409c6df 100644 --- a/examples/intro-to-notion-api/README.md +++ b/examples/intro-to-notion-api/README.md @@ -17,10 +17,10 @@ The files in each directory will build on each other to increase in complexity. ## Table of contents -In case you are looking for example code of a specific task, the files are divided as follows: +In case you are looking for example code for a specific task, the files are divided as follows: - `/basic/1-add-block.js`: Create a new block and append it to an existing Notion page. -- `/basic/2-add-linked-block.js`: Create and append new blocks, and a link to the text of a new block. +- `/basic/2-add-linked-block.js`: Create and append new blocks, and add a link to the text of a new block. - `/basic/3-add-styled-block.js`: Create and append new blocks, and apply text styles to them. - `/intermediate/1-create-a-database.js`: Create a new database with defined properties. - `/intermediate/2-add-page-to-database.js`: Create a new database and add new pages to it. diff --git a/examples/intro-to-notion-api/basic/2-add-linked-block.js b/examples/intro-to-notion-api/basic/2-add-linked-block.js index a3afa581..54424b23 100644 --- a/examples/intro-to-notion-api/basic/2-add-linked-block.js +++ b/examples/intro-to-notion-api/basic/2-add-linked-block.js @@ -45,7 +45,7 @@ async function main() { "Tuscan kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", link: { // Include a url to make the paragraph a link in Notion - url: "https://en.wikipedia.org/wiki/Tuscan _kale", + url: "https://en.wikipedia.org/wiki/Kale", }, }, }, diff --git a/examples/intro-to-notion-api/basic/3-add-styled-block.js b/examples/intro-to-notion-api/basic/3-add-styled-block.js index 8de9e737..7919638e 100644 --- a/examples/intro-to-notion-api/basic/3-add-styled-block.js +++ b/examples/intro-to-notion-api/basic/3-add-styled-block.js @@ -45,7 +45,7 @@ async function main() { "Tuscan kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", link: { // Paragraph link - url: "https://en.wikipedia.org/wiki/Tuscan _kale", + url: "https://en.wikipedia.org/wiki/Kale", }, }, annotations: { From 3ee9960afa03aeb1e00b313dbe48f26b9d7a3d6b Mon Sep 17 00:00:00 2001 From: Jess Mitchell Date: Wed, 6 Sep 2023 10:38:10 -0400 Subject: [PATCH 10/10] add console for querying --- examples/intro-to-notion-api/intermediate/3-query-database.js | 1 + examples/intro-to-notion-api/intermediate/4-sort-database.js | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/intro-to-notion-api/intermediate/3-query-database.js b/examples/intro-to-notion-api/intermediate/3-query-database.js index 16d3ae40..535d3716 100644 --- a/examples/intro-to-notion-api/intermediate/3-query-database.js +++ b/examples/intro-to-notion-api/intermediate/3-query-database.js @@ -32,6 +32,7 @@ async function addNotionPageToDatabase(databaseId, pageProperties) { } async function queryDatabase(databaseId) { + console.log("Querying database...") // This query will filter database entries and return pages that have a "Last ordered" property that is more recent than 2022-12-31. Use multiple filters with the AND/OR options: https://developers.notion.com/reference/post-database-query-filter. const lastOrderedIn2023 = await notion.databases.query({ database_id: databaseId, diff --git a/examples/intro-to-notion-api/intermediate/4-sort-database.js b/examples/intro-to-notion-api/intermediate/4-sort-database.js index bc0ef8c7..36b3ffe4 100644 --- a/examples/intro-to-notion-api/intermediate/4-sort-database.js +++ b/examples/intro-to-notion-api/intermediate/4-sort-database.js @@ -33,6 +33,7 @@ async function addNotionPageToDatabase(databaseId, pageProperties) { } async function queryAndSortDatabase(databaseId) { + console.log("Querying database...") // This query will filter and sort database entries. The returned pages will have a "Last ordered" property that is more recent than 2022-12-31. Any database property can be filtered or sorted. Pass multiple sort objects to the "sorts" array to apply more than one sorting rule. const lastOrderedIn2023Alphabetical = await notion.databases.query({ database_id: databaseId,