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..8409c6df --- /dev/null +++ b/examples/intro-to-notion-api/README.md @@ -0,0 +1,97 @@ +# 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 two sections: + +1. `basic` +2. `intermediate` + +(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. + +## Table of contents + +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 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. +- `/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 + +### 1. Clone project and install dependencies + +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: + +```zsh +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 you can 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 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) + +### 3. Give the integration access to your page + +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. +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: + +```zsh +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 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 Developers Slack group](https://join.slack.com/t/notiondevs/shared_invite/zt-20b5996xv-DzJdLiympy6jP0GGzu3AMg). 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 00000000..d0e837b6 Binary files /dev/null and b/examples/intro-to-notion-api/assets/page_id.png differ diff --git a/examples/intro-to-notion-api/basic/1-add-block.js b/examples/intro-to-notion-api/basic/1-add-block.js new file mode 100644 index 00000000..a245215d --- /dev/null +++ b/examples/intro-to-notion-api/basic/1-add-block.js @@ -0,0 +1,45 @@ +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 }) + +/* +--------------------------------------------------------------------------- +*/ + +/** + * 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", // This is the text that will be displayed in Notion + }, + }, + ], + }, + }, + ], + }) + + // Print the new block(s) response + 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..54424b23 --- /dev/null +++ b/examples/intro-to-notion-api/basic/2-add-linked-block.js @@ -0,0 +1,62 @@ +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 }) + +/* +--------------------------------------------------------------------------- +*/ + +/** + * 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: "Tuscan kale", // This is the text that will be displayed in Notion + }, + }, + ], + }, + }, + { + paragraph: { + rich_text: [ + { + text: { + content: + "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/Kale", + }, + }, + }, + ], + }, + }, + ], + }) + + // Print the new block(s) response + console.log(linkedTextResponse) +} + +main() 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 new file mode 100644 index 00000000..7919638e --- /dev/null +++ b/examples/intro-to-notion-api/basic/3-add-styled-block.js @@ -0,0 +1,70 @@ +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 }) + +/* +--------------------------------------------------------------------------- +*/ + +/** + * 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({ + block_id: blockId, + children: [ + { + heading_3: { + rich_text: [ + { + text: { + content: "Tuscan kale", + }, + }, + ], + }, + }, + { + paragraph: { + rich_text: [ + { + text: { + // Paragraph text + content: + "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/Kale", + }, + }, + annotations: { + // Paragraph styles + bold: true, + italic: true, + strikethrough: true, + underline: true, + color: "green", + }, + }, + ], + }, + }, + ], + }) + + // Print the new block(s) response + 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..589a403b --- /dev/null +++ b/examples/intro-to-notion-api/intermediate/1-create-a-database.js @@ -0,0 +1,59 @@ +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 }) + +/* +--------------------------------------------------------------------------- +*/ + +/** + * 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", + page_id: pageId, + }, + title: [ + { + type: "text", + text: { + content: "New database name", + }, + }, + ], + properties: { + // These properties represent columns in the database (i.e. its schema) + "Grocery item": { + type: "title", + title: {}, + }, + Price: { + type: "number", + number: { + format: "dollar", + }, + }, + "Last ordered": { + type: "date", + date: {}, + }, + }, + }) + + // Print the new database response + 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 new file mode 100644 index 00000000..5d1ab132 --- /dev/null +++ b/examples/intro-to-notion-api/intermediate/2-add-page-to-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 }) + +/* +--------------------------------------------------------------------------- +*/ + +/** + * 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: { + database_id: databaseId, + }, + properties: pageProperties, + }) + console.log(newPage) +} + +async function main() { + // Create a new database + const newDatabase = await notion.databases.create({ + parent: { + type: "page_id", + page_id: pageId, + }, + title: [ + { + type: "text", + text: { + content: "Grocery list", + }, + }, + ], + properties: { + // These properties represent columns in the database (i.e. its schema) + "Grocery item": { + type: "title", + title: {}, + }, + Price: { + type: "number", + number: { + format: "dollar", + }, + }, + "Last ordered": { + type: "date", + date: {}, + }, + }, + }) + + // 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++) { + // Add a few new pages to the database that was just created + await 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 new file mode 100644 index 00000000..535d3716 --- /dev/null +++ b/examples/intro-to-notion-api/intermediate/3-query-database.js @@ -0,0 +1,102 @@ +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 }) + +/* +--------------------------------------------------------------------------- +*/ + +/** + * 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, // Note: Page properties must match the schema of the database + }) +} + +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, + filter: { + property: "Last ordered", + date: { + after: "2022-12-31", + }, + }, + }) + + // Print filtered results + console.log('Pages with the "Last ordered" date after 2022-12-31:') + console.log(lastOrderedIn2023) +} + +async function main() { + // Create a new database + const newDatabase = await notion.databases.create({ + parent: { + type: "page_id", + page_id: pageId, + }, + title: [ + { + type: "text", + text: { + content: "Grocery list", + }, + }, + ], + properties: { + // These properties represent columns in the database (i.e. its schema) + "Grocery item": { + type: "title", + title: {}, + }, + Price: { + type: "number", + number: { + format: "dollar", + }, + }, + "Last ordered": { + type: "date", + date: {}, + }, + }, + }) + // 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++) { + // 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) +} + +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 new file mode 100644 index 00000000..36b3ffe4 --- /dev/null +++ b/examples/intro-to-notion-api/intermediate/4-sort-database.js @@ -0,0 +1,110 @@ +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 }) + +/* +--------------------------------------------------------------------------- +*/ + +/** + * 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, // Note: Page properties must match the schema of the database + }) +} + +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, + filter: { + property: "Last ordered", + date: { + after: "2022-12-31", + }, + }, + sorts: [ + { + property: "Grocery item", + direction: "descending", + }, + ], + }) + + // Print filtered/sorted results + console.log( + 'Pages with the "Last ordered" date after 2022-12-31 in descending order:' + ) + console.log(lastOrderedIn2023Alphabetical) +} + +async function main() { + // Create a new database + const newDatabase = await notion.databases.create({ + parent: { + type: "page_id", + page_id: pageId, + }, + title: [ + { + type: "text", + text: { + content: "Grocery list", + }, + }, + ], + properties: { + // These properties represent columns in the database (i.e. its schema) + "Grocery item": { + type: "title", + title: {}, + }, + Price: { + type: "number", + number: { + format: "dollar", + }, + }, + "Last ordered": { + type: "date", + date: {}, + }, + }, + }) + // 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++) { + // 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) +} + +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" }, + }, + }, +] 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" + } +}