How to use Notion API with NextJS
Tags: productivity, nextjs, node, database
Published: 2021-05-30 14:27:46

Notion API is finally here, and it's so cool. But you must be wondering what is Notion in the first case? Well, it's a powerful productivity tool for managing your daily day-to-day tasks, or maybe jotting down a lot of ideas you want to put up in your next blog? There are unlimited possibilities. 

I myself found it annoying at first because I have a habit of writing down things instead of typing them out on a notepad. But turns out, it did boost my productivity moreover, it's much more noticeable when you are working with a team.

Now imagine if you could display all these data to a front-end, and update them directly on the Notion database instead of pushing some extra line of code. Your favorite tool now has its own API!

This tutorial is beginner-friendly, so don't hesitate. I assure you, the result is satisfying.

Here are the steps we'll be going through,
1. [Create a new database on Notion.](#create-a-new-database-on-notion)
2. [Making a new integration.](#making-a-new-integration)
3. [Setting up the back-end.](#setting-up-the-backend)
4. [Fetching data from the database.](#fetching-data-from-the-database)
5. [Modifying the API call.](#modifying-the-api-call)
6. [Displaying the data on a NextJS project.](#displaying-the-data-on-a-nextjs-project)

---

> Source code: [GitHub](https://github.com/GeoBrodas/notion-project/)

---

## Create a new database on Notion.

Go ahead and make a new Notion account, if you haven't made one.

Create a new page.

![add databse.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1622120222950/dspcKphoE.png)

There are lots of templates and different databases available. Here we will be building a project database using the kanban board. Next time whenever you complete an ongoing project, move it to the "Completed" section, and you can see the change instantly on your website.

Go ahead and add some projects, dummy or actual, which you have already completed.

![dummy.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1622121121085/0T26-R2-T8.png)

## Making a new integration. 

Now let's connect our database to a new integration. Go to the official page of [Notion API](https://developers.notion.com/) and click on 'My Integrations' in the top-right corner. 

Make a new integration. 

![integrations.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1622122190168/ZM9xVl9Uc.png)
 
Copy the Token ID somewhere safe, we'll be using it for authentication ahead.

Now let's connect our database to the newly created integration.

Simply, head over to the new page we created, click on **Share**, and search for the integration we just created.
![Slide 16_9 - 1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1622203232748/wjhri1Hlp.png)

## Setting up the backend.

Now, we'll make our own API, which will fetch the data through Notion API and then filter through the data, to display what is actually relevant.

Go ahead and run `npm init -y`.

Make sure you have the latest NodeJS version installed.

We'll need three packages, 
```bash
npm install express @notionhq/client dotenv
```
Install `nodemon`, to keep the server active throughout the process.
```bash
npm install nodemon --save-dev
```
Go over to the `package.json` file, and add a new script for `nodemon`.
```bash
"dev" : "nodemon index.js"
```
Make a new `.env` file, and add the Token ID we created.
```js
NOTION_TOKEN_ID=yourtokenid
```
Head over to the `index.js` file, and initialize `dotenv` and require the Auth Client from the Notion SDK.
```js
const dotenv = require('dotenv').config()
const { Client } = require('@notionhq/client')
```
Now, we need to acquire the database ID to fetch data from the new page we created.

There are 2 ways to find this out, either you can use [Postman](https://www.postman.com/) (or any other API testers) and make a `GET` request to https://api.notion.com/v1/databases with the Bearer Token ( the Token ID).

![postman.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1622206056989/RcVi9Q_uy.png)
Or head over to the `index.js` file, create a new `Client`
```js
const notion = new Client({
  auth: process.env.NOTION_TOKEN,
})
```
Now, create an `async` function.
```js
const listDatabases = async () => {
  const res = await notion.databases.list();
  console.log(res);
};

listDatabases();
```
Now run `npm run dev`, and if you check the console, you'll be able to view the same result.

Head over to the `.env` file, and add this database ID
```js
NOTION_DATABASE_ID=yourdatabaseid
```
Now let's set up the express server,
```js
const express = require('express');

const app = express( )

app.listen(process.env.PORT || 3000, console.log('Server is up and running!') )
```
## Fetching data from the database.
Now let's fetch the raw data we get from the Notion API.

Start with defining a constant `payload`, which we will pass through the request as follows
```js
const getProjects = async ( ) => {
    const payload = {
        path: `databases/${database_id}/query`,
        method: 'POST'
    }
}
```
The path is mentioned in the Notion API documentation, although we won't be needing the root URL, since we are using the SDK.
![query-notion.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1622359176035/N9LlTy9ss.png)
*Source: [Notion API documentation](https://developers.notion.com/reference/post-database-query)*

From the response, we just need the `results` object, hence destructure the object and try to log the response onto the console.
```js
const database_id = process.env.NOTION_DATABASE_ID

const getProjects = async ( ) => {
     const payload = {
        path: `databases/${database_id}/query`,
        method: 'POST'
    };

  const { results } = await notion.request(payload);
return results;
}

const data = await getProjects( );
console.log(data);
```
You should now be getting the list of cards, we made previously in JSON format as follows.
![results-1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1622366334216/J2VPqLA9M.png)

## Modifying the API call.
As you have seen, the response has a lot of junk data. In this section, we'll filter through the data, and send a personalized object.

Now the objective is to get only the cards, that have the marked status "Completed".

Inside the `getProjects` function, let's map through the response, and return a customized object back.
```js
const projects = results.map( page => {
    if ( page.properties.Status.select.name === 'Completed' ) {
        return {
        id: page.id,
        title: page.properties.Name.title[0].text.content,
        status: page.properties.Status.select.name,
      }
    }
} )
```
Now, `projects` will be an array of objects each containing an object with the status 'Completed'.

It will also have some null values. We can remove these by using the `filter` function.

This can be implemented in the return statement as follows,
```js
return projects.filter(project => project);
```
Now, the final response should only contain an array of objects with the status 'Completed'.
![results-final.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1622369774388/LE-NmQ2bz.png)

What's left now is to set up a route in our express server.
```js
app.get('/projects', async (req, res) => {
  const projects = await getProjects( )
  res.json(projects)
})
```

## Displaying the data on a NextJS project.

Our API is Ready! 

The final task is to display it to a front-end. Go ahead and initialize a new NextJS project. (or if you have an existing project)
```bash
npx create-next-app notion-api
```
Go to `pages/index.js`.
( or any other route you prefer, depending on the type of project your working on)

Make a new `.env.local` file to store the API URL. NextJS comes in-built with environment variables support.

```js
NEXT_API=https://localhost:8000/projects
```
In NextJS, to receive data from the endpoint, NextJS uses an `async` function called `getStaticProps`. By using this function, NextJS will pre-render the data on the server-side on **build** time, rather than fetching the data when the page first loads.
```js
export async function getStaticProps( ) {
  // get posts from our api
  const res = await fetch(process.env.NEXT_API)
  const projects = await res.json()

  return {
    props: { projects },
  }
}
```
We can now get hold of this array, by passing it to the default function.
```js
export default function Home ({ projects }) {
    return (
        <ul>
            { 
                 projects && projects.map( (project, index) => <li key={project.id}>{project.title}</li>) 
             }
        </ul>
    )
}
```
Congrats! You're doing a great job!

You can check what I did with Notion API on my portfolio page [here](https://sh-ort.app/cldeq).

## Resources
I could build this through Traversy Media's video on Youtube, so if you get stuck, check out his tutorial!
{% youtube 9JdP-S3crt8 %}

## Thanks for Reading!🎉
The Notion API can be tweaked in many ways. You can integrate it with Slack, Typeform, etc. It's a really powerful tool. As a personal advice, if you haven't worked with API's before, I think Notion API is just the place. It's really simple and has a great documentation with plenty of video tutorials online. Hit me up on [Twitter](https://sh-ort.app/owefm) with your creation!

> If you need the source code, do let me know in the comments section below, I'll respond as soon as possible👍

## Support me 🙌
My blogs are powered by coffees, if you feel I deserve one, Thanks❤
<a href="https://www.buymeacoffee.com/geobrodas"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=geobrodas&button_colour=FF5F5F&font_colour=ffffff&font_family=Cookie&outline_colour=000000&coffee_colour=FFDD00"></a>