makenotion / notion-sdk-js Goto Github PK
View Code? Open in Web Editor NEWOfficial Notion JavaScript Client
Home Page: https://developers.notion.com/docs
License: MIT License
Official Notion JavaScript Client
Home Page: https://developers.notion.com/docs
License: MIT License
Hey! Congratulations on public notion API and awesome work on minimal and typed js SDK 💯
As of the current version, this package seems to only work with node.js, which makes missing lots of opportunities for supporting non-nodejs environments such as Deno, Cloudflare workers, universal frameworks like Nuxt.js , and frontend libraries like vue-notion this can open LOTS of new opportunities for using sdk.
For this change, we need to avoid depending on got
and using a universal alternative (fetch
) API. Since request
is already refactored, it would be easy to allow providing custom client implementation or creating multi-target bundles (see ohmyfetch as an example) that importing @notionhq/client
be as is now but having @notionhq/client/isomorphic
import (or /node
import) that is preconfigured with either node-fetch or got or faster node clients like nodejs/undici / undici-fetch
I can propose a PR if above seems reasonable for purpose of notion-sdk.
All requests should include the Notion-Version
HTTP header.
There should be a default value built-in. The default value should be the latest available on the Notion API, and the methods and types in the Client should match that version. If the default version changes, the major version of this client should also change.
In the future, the Client
should accept an option for the value of the Notion-Version
header. At this point, we may also want to store information about the range of compatible versions in the client, so that a warning can be emitted if the client is being used against an incompatible version. Compatibility most likely depends on the specific method/endpoint.
It would be really useful if there was a method to fetch a whole page as Markdown
Since there's already a way to do it on the website, I don't think it would be too much trouble adding it to the public api
Are there any plans to implement this officially?
both the SDK, API returns 404 error when i request page properties update, but everything works fine when requesting page information
const PAGEID = "5044618ceecc499f891f270e3bb66b26";
workspace.pages
.retrieve({
page_id: PAGEID,
})
.then((page) => {
const titleProperty = (page.properties["title"] as TitlePropertyValue)
.title;
const title = titleProperty[0].plain_text;
console.log("page ["+title+"], id#", page.id);
workspace.request({
path: `pages/${PAGEID}`,
method: "patch",
body: {
properties: {
title: createTitle(`${title}1`),
},
},
})
});
function createTitle(content: string): TitlePropertyValue {
return {
type: "title",
id: "8868",
title: [
{
type: "text",
plain_text: content,
text: {
content,
},
annotations: {
bold: false,
italic: false,
strikethrough: false,
underline: false,
code: false,
color: "default",
},
},
],
};
}
ps: the (private )page has the integration permission
When implicitly using the PropertyValue
type to update a page's property, TypeScript requires that the id
and type
fields be included.
Example:
notion.pages.update({
page_id: taskId,
properties: {
'Do On': {
date: {
start: '2021-05-20'
}
}
}
})
Gives the following error:
test.ts:41:13 - error TS2322: Type '{ date: { start: string; }; }' is not assignable to type 'PropertyValue'.
Type '{ date: { start: string; }; }' is missing the following properties from type 'DatePropertyValue': type, id
41 'Do On': {
As per the example on this page, these fields should not be required. Furthermore, if this request is made fully in JS it works without a problem.
The trivial fix would be to make these fields optional:
export interface PropertyValueBase {
id?: string;
type?: string;
}
But (perhaps obviously), this is probably not desirable. Perhaps PagesUpdateBodyParameters
should use something like PropertyUpdateValue
where these values are optional?
I'd be more than happy to work on a PR for this issue if necessary.
Errors should be separated into the following kinds:
unauthorized
restricted_resource
object_not_found
rate_limited
4xx
range that aren't explicitly listed above. This is how 400 Bad Request
responses for problems like missing parameters are categorized.
invalid_json
, invalid_request_url
, invalid_request
, validation_error
.conflict_error
5xx
range
internal_server_error
service_unavailable
Each kind of error should have a unique value assigned to the code
property. Each kind of error can have also have a unique class.
Each error should also have the following properties:
status: number
- The HTTP status code (e.g. 404
)message: string
- The "message"
property from the response bodyheaders: { [string]: string | string[] }
- The HTTP response headersbody: string
- The unparsed HTTP bodyWe can categorize each kind of error as logical or ephemeral in order to build automatic retries. For example, an error with authorization such as a 401 HTTP response is logical. No matter how many times it is retried, unless a user does something to change the authorization permissions, it will result in the same error. But an error with opening the TCP connection to make a request is ephemeral because there's some chance that simply trying again would be successful. A better term for "ephemeral" might be "possibly non-logical", but that's not as concise. We can add this later.
I created a database of few pages and added page mentions to the default Name property.
I'm getting this as in Name property of each page when querying the database.
"id":"title",
"type":"title",
"title":[
{
"type":"text",
"text":{
"content":" ",
"link":null
},
"annotations":{
"bold":false,
"italic":false,
"strikethrough":false,
"underline":false,
"code":false,
"color":"default"
},
"plain_text":" ",
"href":null
}
]
I should get content as page mention title and link as its notion public page url.
Is this fine?
It'd be great to have an OpenAPI spec to enable robust documentation and client generation.
I want to use the Notion API.
Can these be used in React?
I wrote it like this.
import { Client } from '@notionhq/client';
function App() {
const notion = new Client({ auth: process.env.REACT_APP_INTEGRATION_TOKEN });
return (
<div className="App">
// ...more
In Next.js, Module not found: Can't resolve 'dns'
.
In CRA, Module not found: Can't resolve 'http2'
.
is displayed.
package.json
{
"name": "lesson-notion-api",
"version": "0.1.0",
"private": true,
"dependencies": {
"@notionhq/client": "^0.1.3",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
from #20
Another shortcoming is that there isn't a good separation between "input" types and "output" types. This matters in situations where a method accepts, for example, a Block in its parameters. At call time, a block won't have properties like id - those are assigned by the server. However, the Block type has id set as a non-optional property. This is a real issue and should be handled in a bugfix.
There seems to be a slight inconsistency with what a database retrieve returns and the typescript definition for files:
The typescript definition is as follows:
export declare type Property = TitleProperty | RichTextProperty | NumberProperty | SelectProperty | MultiSelectProperty | DateProperty | PeopleProperty | FileProperty | CheckboxProperty | URLProperty | EmailProperty | PhoneNumberProperty | FormulaProperty | RelationProperty | RollupProperty | CreatedTimeProperty | CreatedByProperty | LastEditedTimeProperty | LastEditedByProperty;
export interface FileProperty extends PropertyBase {
type: "file";
file: Record<string, never>;
}
However the database retrieve returns:
{"id":"L;D\\","type":"files","files":[]}
Describe the bug
I receive the following error when trying to make a create page requests using the NodeJS library. I am making the request inside of my NodeJS app. I am positive that the database is linked as I am able to add entries to the database if I use cURL or if I write the http request manually using axios.
See below for the request which is resulting in the error.
const notion = new Client({
auth: process.env.NOTION_TOKEN,
logLevel: LogLevel.DEBUG,
})
router.post('/api/post/addentry',` (req, res) => {
let data = {
parent: {
database_id: process.env.DB_ID,
},
properties: {
Name: {
type: 'title',
title: [
{
text: {
content: name,
},
},
],
},
Date: {
date: {
start: date,
},
},
Completed: {
select: { name: completed },
},
},
};
(async () => {
try {
console.log(data);
const response = await notion.pages.create(data);
console.log(response);
res.send('Entry Added');
} catch (error) {
if (error.code === APIErrorCode.ObjectNotFound) {
//
// For example: handle by asking the user to select a different database
//
res.send('Object not found');
} else {
// Other error handling code
console.error(error)
res.send('Error');
}
}
})();
})
TypeError: Object.fromEntries is not a function
I have followed the documentation here for format:
To Reproduce
Node version: 10.19.0
Express version: ~4.16.1
axios version: ^0.21.1
Notion JS library version: ^0.1.8
Expected behavior
Expect new page to be created and added to the linked database.
All Block types currently have types with a text
key, paragraph
type as an example here:
export interface ParagraphBlock extends BlockBase {
type: 'paragraph';
text: RichText[];
children?: BlockBase[];
}
The documentation however states that the text for paragraphs is actually found in a a key paragraph
, for headings it's in heading_#
and so on. When using the API the text is where the API reference states it is, so it's just the types which are wrong here.
I'm not sure if it is missing in SDK or the dummy success response given in API document are incorrect..
If you see the API response for List Databases
& Retrieve a database
API's you will notice that there is Property with the type text
and when I look into source code I do not see any Text type property.
Would it possible for anyone to clear this confusion for me?
API document
Retrieve a database
List databases.
How do I use the SDK to complete the oauth flow?
I am trying to talk to the notion api via a webpage, but it is getting blocked by the browser.
I think this should be possible to fix on the server side by adding the "Access-Control-Allow-Origin: *" in the reply header.
A current workaround for this is to run the browser with CORS check disabled.
Given the example below:
const { Client } = require('@notionhq/client');
const notion = new Client({
auth: process.env.NOTION_TOKEN,
});
(async () => {
const response = await notion.users.list();
console.log(response);
})();
The client emits an error: TypeError: Cannot read property 'start_cursor' of undefined
. If I add an empty object to the method call, it works.
Report bugs here only for the Node JavaScript library.
If you're having problems using Notion's API, or have any other feedback about the API, please reach out to support by going to developers.notion.com, scroll to the bottom and click on Help
.
Describe the bug
When using the formula filter there is 1 level too much nesting in the type
To Reproduce
Node version: 14
Notion JS library version: 0.1.8
Steps to reproduce the behavior:
attempt to search a function column in a database.
following the types it wants you to write
formula: {
number: {
number: {
equals: 1,
}
},
},
this looks as tho it is because the formula object uses the filters e.g. NumberFilter
which also have a property e.g. number?
also defined in them
Expected behavior
should accept the following
formula: {
number: {
equals: 1,
},
}
Screenshots
Please include any screenshots that help explain your problem.
Additional context
Add any other context about the problem here.
Not sure if this is the right place to ask this. But, it would really help if we can get the data for the unsupported blocks. It doesn't matter even if it's not structured properly. When you do add support for those blocks, you can add a proper structure to it.
It's seems you left a console.log building the error in your code: https://github.com/makenotion/notion-sdk-js/blob/main/src/errors.ts#L84
I have a bunch of databases with similar properties. I have a page which contains the linked databases. How can I programmatically set the views (e.g. board view with sort and filter, etc) using the API?
I'm trying to fill in a database field of the date type:
await notion.request({
path: 'pages',
method: 'post',
body: {
parent: { database_id: '738ab074-8597-4fc8-b220-813c3dc75528' },
properties: {
'Text': [{ text: { content: 'someText' } }],
'Date': { name: 'Date', date: { start: '2021-04-26' } }
}
}
})
But I get an error:
Client warn: request fail {
code: 'validation_error',
message: 'Body Validation Failed. Fix the following:\n' +
'Invalid property value for: "Date".'
}
Since I started using Notion API and this SDK, I wanted to work around typing.
Because the notion API format is quite heavy, it's easy to do mistakes when filling properties, at page update for example.
I opened a pull request #103 last week on this repository to show an example of what could be done to enable body validation by typescript during development.
This PoC shows how we could use generic typing to validate the page update method inputs based on the page definition.
Would be glad if you can give me some feedbacks !
const issuesInDatabase = await getIssuesFromDatabse();
should be
const issuesInDatabase = await getIssuesFromDatabase();
Running into issues related to http2
when used with a react application created using create-react-app
.
Link to test repo
create-react-app
@notionhq/client
as a dependencyconst { Client } = require("@notionhq/client")
to App.js
Report bugs here only for the Node JavaScript library.
If you're having problems using Notion's API, or have any other feedback about the API, please reach out to support by going to developers.notion.com, scroll to the bottom and click on Help
.
Describe the bug
When trying
const blocks = notion.blocks.children.list({});
I'm getting missing path_id error from sdk log
body: '{"object":"error","status":400,"code":"validation_error","message":"path failed validation: path.id should be a valid uuid, instead was `\\"undefined\\"`."}'
I'm able to pass path_id directly to api using postman, but I'm not sure how the same can be passed in the sdk method.
To Reproduce
Node version: v12.18.3
Notion JS library version: 2021-05-13
Steps to reproduce the behavior:
Expected behavior
A clear and concise description of what you expected to happen.
Create module
const { Client } = require("@notionhq/client");
const notion = new Client({
auth: process.env.NOTION_TOKEN
});
module.exports = notion;
Call notion method to retrieve blocks
function retrieveFAQ() {
console.log("calling notion sdk");
const blocks = notion.blocks.children.list({});
blocks.catch(errors => {
console.log(errors);
}).then(response => {
console.log(response);
});
return blocks;
}
Screenshots
Please include any screenshots that help explain your problem.
Additional context
Add any other context about the problem here.
Hi all,
Describe the bug
I created a "Relation" property type in a table to see the date from another table, so I set a column with the "Rollup" prop type of a Date type "Tentative" like this:
Then, in the column "Delayed?" I selected the "Formula" type to compare the date and when I tried to set the formula, all properties are as String, so "Started" and "Tentative" are String type instead of Date type format.
Additional context
So, If I try using these properties in a Date Formula it shows like this:
Thanks for opening up the Notion API. This is wonderful news and I am looking forward to develop integrations!
I use Python and Go on a regular basis and would like to develop Python and Go clients which would be easier if there was a Swagger API spec or something similar. Do you have plans to share the API spec?
The MultiSelectPropertyValue type has a bug where it expects the multi_select to be a single SelectOption instead of an array of SelectOption[]
export interface MultiSelectPropertyValue extends PropertyValueBase {
type: 'multi_select';
multi_select: {
id: string;
name: string;
color: Color;
};
}
Hello,
database_id
isn't compliant compared to logLevel
or baseUrl
.
Please, use lowerCamelCase everywhere.
Thank youuuuuuuu 🙌🏻
I was able to get a 400 invalid_request_url
error, and the resulting error object did not have the code
property set.
APIResponseError: Request to Notion API failed with status: 400
at Object.buildRequestError (/Users/ankur/Developer/play/js-sdk-smoke/node_modules/@notionhq/client/build/src/errors.js:75:20)
at Client.request (/Users/ankur/Developer/play/js-sdk-smoke/node_modules/@notionhq/client/build/src/Client.js:206:43)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async /Users/ankur/Developer/play/js-sdk-smoke/index.js:20:22 {
code: undefined,
status: 400,
First of all, I want to thank everyone at notion for the API 👏🏼 🥳
My question is how would I go about deleting a database item using the JS SDK?
I've tried the following but no go:
await notion.request({
path: `pages/${data.pageId}`,
method: 'DELETE',
body: {
parent: { database_id: databaseId }
}
})
I am adding data to the database using post request to /pages.
It only works when I give {name: value} when value is already defined as an option in the notion table.
If a new option is provided, the following error message shows up
rZ?P is an invalid select option
It'd be nice to be able to access the "type-specific data" in a property object without caring about what the type actually is. For example, to be able to do this: const propertyData = property[property.type]
. Typescript won't let you do this though because there is no index signature on the PropertyValue
type.
If I try to write this function:
const getAllPropertyData = async () => {
const databaseId = process.env.NOTION_DATABASE_ID ?? "";
try {
const { results } = await notion.databases.query({ database_id: databaseId });
const propertiesData = results.map(({ properties }) => {
// type PropertyValue
const property = properties.Day;
// "number" | "title" | "rich_text" | "select" ... etc.
const type = property.type;
// Type error here.
const propertyData = property[type];
return propertyData;
});
return propertiesData;
} catch (error) {
console.error(error);
}
}
I'll get the following type error:
Element implicitly has an 'any' type because expression of type '"number" | "title" | "rich_text" | "select" | "multi_select" | "date" | "formula" | "rollup" | "people" | "files" | "checkbox" | "url" | "email" | "phone_number" | "created_time" | "created_by" | "last_edited_time" | "last_edited_by"' can't be used to index type 'PropertyValue'.
But the type
always refers to another key in the property object as it states in the working with databases guide here. It makes sense then to have an index signature to allow you to access property data in this way.
I think something like this would work:
export interface PropertyValueBase {
[typeSpecificDataKey: string]: RichText[] | number | Select // ... etc. ;
id: string;
type: string;
}
��I have a search script that queries one specific database with pages, that should filter all pages that match the search query, but it doesn't seem to work as expected. I've done a few queries now, but have found one that should give results and it doesn't. Only when I manually update a note it will be in the results. To better illustrate my issue I've made a screencast. (see below)
To Reproduce
Node version: v14.15.1
Notion JS library version: 0.1.8
Steps to reproduce the behavior:
import { Client } from "@notionhq/client"
import { config } from "dotenv"
// const { Client } = require('d@notionhq/client');
config()
const notion = new Client({ auth: process.env.NOTION_API_KEY });
(async () => {
const response = await notion.search({
query: 'untitled',
page_size: 100
});
console.warn(response);
})();
Expected behavior
List of all my pages with '...untitled...' in the name
Additional context
My thought is that most of these pages (maybe all) are imported from Dropbox paper and/or Evernote and maybe there in lies the issue?
How do I list all pages and get the hierarchy? Is there an example to do this?
The DateMention
interface says its date
property is a DatePropertyValue
but the API just returns an object with start
and end
properties.
interface DateMention {
type: "date";
date: DatePropertyValue;
}
interface DatePropertyValue extends PropertyValueBase {
type: "date";
date: {
start: string;
end?: string;
};
}
But the returned mention object looks like:
{ type: 'date', date: { start: '2021-05-29', end: null } }
The other Mention types just have the data in the typed key.
Hi!
Firstly, congrats for the nice work on the DSK types DSL modelling allowing exhaustive "pattern matching" 🙌
Said that, I am not sure if this is a bug or I am missing something, let me explain it with an example 😊
const queryFilterSelectFilterTypeBased: SelectFilter = {
property: "Status",
equals: "Blocked"
}
this.client.databases.query({
database_id: this.kanbanDatabaseId,
filter: queryFilterSelectFilterTypeBased
});
Log:
building the error
Client warn: request fail {
code: 'validation_error',
message: 'body failed validation. Fix one: body.filter.or should be defined, instead was `undefined`. body.filter.and should be defined, instead was `undefined`. body.filter.title should be defined, instead was `undefined`. body.filter.text should be defined, instead was `undefined`. body.filter.number should be defined, instead was `undefined`. body.filter.checkbox should be defined, instead was `undefined`. body.filter.select should be defined, instead was `undefined`. body.filter.multi_select should be defined, instead was `undefined`. body.filter.date should be defined, instead was `undefined`. body.filter.people should be defined, instead was `undefined`. body.filter.files should be defined, instead was `undefined`. body.filter.url should be defined, instead was `undefined`. body.filter.email should be defined, instead was `undefined`. body.filter.phone should be defined, instead was `undefined`. body.filter.relation should be defined, instead was `undefined`. body.filter.created_by should be defined, instead was `undefined`. body.filter.created_time should be defined, instead was `undefined`. body.filter.last_edited_by should be defined, instead was `undefined`. body.filter.last_edited_time should be defined, instead was `undefined`. body.filter.formula should be defined, instead was `undefined`. body.filter.rollup should be defined, instead was `undefined`.'
}
Unexpected result:
building the error
log output: Already being handled in #48body.filter
defining the property typeTaking a look to the SelectFilter
type, it is being defined as:
export interface SelectFilter extends SinglePropertyFilterBase {
equals?: string;
does_not_equal?: string;
is_empty?: true;
is_not_empty?: true;
}
export interface SinglePropertyFilterBase {
property: string;
}
So, at the end, it will result in constructing an object like the previous one:
{
"property": "Status",
"equals": "Blocked"
}
And looking at how the Notion SDK client implements the databases.query
operation, it would be passing through this very same object to the HTTP endpoint without any previous modification:
https://github.com/makenotion/notion-sdk-js/blob/main/src/Client.ts#L183
Taking a look to the Filter object documentation in the API docs, it seems to be having an additional nesting level specifying the property type of the property being queried. text
in the documented example:
{
"property": "Landmark",
"text": {
"contains": "Bridge"
}
}
It seems that the SDK would not be adding that additional level, so lets try executing the following, even if TypeScript produces a compiling error:
const statusFilterHttpSpecsBased: Filter = {
property: "Status",
select: { equals: status }
};
this.client.databases.query({
database_id: this.kanbanDatabaseId,
filter: statusFilterHttpSpecsBased
});
It works! 🎉
Despite the obvious mismatch at types level for TypeScript:
TS2322: Type '{ property: string; select: { equals: string; }; }' is not assignable to type 'Filter'. Object literal may only specify known properties, and 'select' does not exist in type 'Filter'.
I could be missing anything, so please, feel free to point me what is it if I am mistaken 🙏
If not, which approach would you prefer in order to fix it?
Thanks!
Example code should use clear and consistent style, just like the rest of the library code. In order to lint the example code, we may need a separate (or modified) ESLint configuration because the current configuration is aimed at linting TypeScript code (not JavaScript).
notion.databases.list
is returning no results. Code is something like:
import { NextApiRequest, NextApiResponse } from "next"
import { notion } from "../../lib/notion"
export default async (req: NextApiRequest, res: NextApiResponse) => {
console.log(await notion.users.list({})) // This one is returning all our users, so the integration works.
console.log(await notion.databases.list({})) // This one is returning { ..., results: [] }, an empty array.
// btw, to both methods I have to pass an empty object else typescript will complain, which is odd.
res.status(200).send("ok")
}
We have lots of databases on our workspace, and a couple of them are even public to the whole web.
notion-sdk-js/src/api-types.ts
Lines 445 to 459 in 5a6f2fa
maybe optional
export interface DateFilter extends SinglePropertyFilterBase {
equals?: string
before?: string
after?: string
on_or_before?: string
is_empty?: true
is_not_empty?: true
on_or_after?: string
past_week?: Record<string, never>
past_month?: Record<string, never>
past_year?: Record<string, never>
next_week?: Record<string, never>
next_month?: Record<string, never>
next_year?: Record<string, never>
}
I'm getting this error when I try to fetch my database using the id of that
Client warn: request fail {
code: 'object_not_found',
message: 'Could not find database with ID: 50d140b9-785e-4c6e-935b-f56f5c4b9215.'
}
Can anyone help me with this?
Client
currently contains the databases.retrieve()
and databases.query()
methods. The remaining methods from the Notion REST API must also be added.
The type definitions for the new methods must also be added. Also, the types for the existing methods can be improved.
For example, when calling client.databases.retrieve({ database_id: someDatabaseId })
, the returned promise rejects with the following error.
RequestError: The `GET` method cannot be used with a body
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.