Giter Club home page Giter Club logo

notion-ruby's Introduction

Unofficial Notion Client for Ruby.

Codacy Badge Build Status Ruby Style Guide Gem Version

  • Read the blog post, which outlines why I built this and some of the functionality.
  • Check out the Gem!

Table of Contents

Getting Started

Installation

to install the gem:

gem install notion

Then, place this at the top of your file:

require 'notion_api'

To get started using the gem, you'll first need to retrieve your token_v2 credentials by signing into Notion online, navigating to the developer tools, inspecting the cookies, and finding the value associated with the token_v2 key.

From here, you can instantiate the Notion Client with the following code:

>>> @client = NotionAPI::Client.new("<insert_v2_token_here>")

Retrieving a Page

A typical starting point is the get_page method, which returns a Notion Page Block. The get_page method accepts the ID (formatted or not) or the URL of the page:

  1. URL → https://www.notion.so/danmurphy/TEST-PAGE-d2ce338f19e847f586bd17679f490e66
  2. ID → d2ce338f19e847f586bd17679f490e66
  3. Formatted ID → d2ce338f-19e8-47f5-86bd-17679f490e66
>>> @client.get_page("https://www.notion.so/danmurphy/TEST-PAGE-d2ce338f19e847f586bd17679f490e66")
>>> @client.get_page("d2ce338f19e847f586bd17679f490e66")
>>> @client.get_page("d2ce338f-19e8-47f5-86bd-17679f490e66")

All three of these will return the same block instance:

#<NotionAPI::PageBlock id="d2ce338f-19e8-47f5-86bd-17679f490e66" title="TEST" parent_id="<omitted>">

The following attributes can be read from any block class instance:

  1. id: the ID associated with the block.
  2. title: the title associated with the block.
  3. parent_id: the parent ID of the block.
  4. type: the type of the block.

To update the title of the page: Update the title of a page

Retrieving a CollectionView Page

This is achieved by passing the ID of the Collection View to the get_page method. Currently, the full URL of a Collection View Page is not supported (next up on the features list!). Once you retrieve the Collection View Page, all of the methods exposed to a normal Collection View instance are available (such as .rows, .row(<row_id>), and all else outlined in Updating a Collection).

Retrieving a Block within the Page

Now that you have retrieved a Notion Page, you have full access to the blocks on that page. You can retrieve a specific block or collection view, retrieve all children IDs (array of children IDs), or retrieve all children (array of children class instances).

Get a Block

To retrieve a specific block, you can use the get_block method. This method accepts the ID of the block (formatted or not), and will return the block as an instantiated class instance:

@page = @client.get_page("https://www.notion.so/danmurphy/TEST-PAGE-d2ce338f19e847f586bd17679f490e66")
@page.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
#<TextBlock id="2cbbe0bf-34cd-409b-9162-64284b33e526" title="TEST" parent_id="d2ce338f-19e8-47f5-86bd-17679f490e66">

Any Notion Block has access to the following methods:

  1. title= → change the title of a block.
>>> @block = @client.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
>>> @block.title # get the current title...
"TEST"
>>> @block.title= "New Title Here" # lets update it...
>>> @block.title
"New Title Here"

For example: Update the title of a block 2. convert → convert a block to a different type.

>>> @block = @client.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
>>> @block.type
"text"
>>> @new_block = @block.convert(NotionAPI::CalloutBlock)
>>> @new_block.type
"callout"
>>> @new_block # new class instance returned...
#<NotionAPI::CalloutBlock:0x00007ffb75b19ea0 id="2cbbe0bf-34cd-409b-9162-64284b33e526" title="New Title Here" parent_id="d2ce338f-19e8-47f5-86bd-17679f490e66">

For example: Convert a page

  1. duplicate→ duplicate the current block.
>>> @block = @client.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
>>> @block.duplicate # block is duplicated and placed directly after the current block
>>> @block.duplicate("f13da22b-9012-4c49-ac41-6b7f97bd519e") # the duplicated block is placed after 'f13da22b-9012-4c49-ac41-6b7f97bd519e'

For example: Convert a page 4. move → move a block to another location.

>>> @block = @client.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
>>> @target_block = @client.get_block("c3ce468f-11e3-48g5-87be-27679g491e66")
>>> @block.move(@target_block) # @block moved to **after** @target_block
>>> @block.move(@target_block, "before") # @block moved to **before** @target_block

For example: move a block

Get a Collection View

To retrieve a collection, you use the get_collection method. This method is designed to work with Table collections, but the codebase is actively being updated to support others:

>>> @page = @client.get_page("https://www.notion.so/danmurphy/TEST-PAGE-d2ce338f19e847f586bd17679f490e66")
>>> @page.get_collection("34d03794-ecdd-e42d-bb76-7e4aa77b6503")
#<NotionAPI::CollectionView:0x00007fecd8859770 @id="34d03794-ecdd-e42d-bb76-7e4aa77b6503", @title="Car Data", @parent_id="9c50a7b3-9ad7-4f2b-aa08-b3c95f1f19e7", @collection_id="5ea0fa7c-00cd-4ee0-1915-8b5c423f8f3a", @view_id="5fdb08da-0732-49dc-d0c3-2e31fccca73a">

Any Notion Block has access to the following methods:

  1. row_ids → retrieve the IDs associated with each row.
>>> @collection = @page.get_collection("34d03794-ecdd-e42d-bb76-7e4aa77b6503")
>>> @collection.row_ids
ent.rb
["785f4e24-e489-a316-50cf-b0b100c6673a", "78642d95-da23-744c-b084-46d039927bba", "96dff83c-6961-894c-39c2-c2c8bfcbfa90", "87ae8ae7-5518-fbe1-748e-eb690c707fac",..., "5a50bdd4-69c5-0708-5093-b135676e83c1", "ff9b8b89-1fed-f955-4afa-5a071198b0ee", "721fe76a-9e3c-d348-8324-994c95d77b2e"]
  1. rows → retrieve each Row, returned as an array of TableRowInstance classes.
>>> @collection = @page.get_collection("34d03794-ecdd-e42d-bb76-7e4aa77b6503")
>>> @collection.rows
#<NotionAPI::CollectionViewRow:0x00007ffecca82078 @id="785f4e24-e489-a316-50cf-b0b100c6673a", @parent_id="9c50a7b3-9ad7-4f2b-aa08-b3c95f1f19e7", @collection_id="5ea0fa7c-00cd-4ee0-1915-8b5c423f8f3a", @view_id="5fdb08da-0732-49dc-d0c3-2e31fccca73a">,..., #<NotionAPI::CollectionViewRow:0x00007ffecca81998 @id="fbf44f93-52ee-0e88-262a-94982ffb3fb2", @parent_id="9c50a7b3-9ad7-4f2b-aa08-b3c95f1f19e7", @collection_id="5ea0fa7c-00cd-4ee0-1915-8b5c423f8f3a", @view_id="5fdb08da-0732-49dc-d0c3-2e31fccca73a">]
  1. row("<row_id>") → retrieve a specific row.
>>> @collection = @page.get_collection("34d03794-ecdd-e42d-bb76-7e4aa77b6503")
>>> @collection.row("f1c7077f-44a9-113d-a156-90ab6880c3e2")
{"age"=>[9], "vin"=>["1C6SRFLT1MN591852"], "body"=>["4D Crew Cab"], "fuel"=>["Gasoline"], "make"=>["Ram"], "msrp"=>[64935], "year"=>[2021], "model"=>[1500], "price"=>[59688], "stock"=>["21R14"], "dealerid"=>["MP2964D"], "colour"=>["Bright White Clearcoat"], "engine"=>["HEMI 5.7L V8 Multi Displacement VVT"], "photos"=>["http://vehicle-photos-published.vauto.com/d0/c2/dd/8b-1307-4c67-8d31-5a301764b875/image-1.jpg"], "series"=>["Rebel"], "newused"=>["N"], "city_mpg"=>[""],...,"engine_cylinder_ct"=>[8], "engine_displacement"=>[5.7], "photos_last_modified_date"=>["11/13/2020 8:16:56 AM"]}

Creating New Blocks

Here's a high-level example: create a callout a block The block types available to the create method are:

  1. DividerBlock
  2. TodoBlock
  3. CodeBlock
  4. HeaderBlock
  5. SubHeaderBlock
  6. SubSubHeaderBlock
  7. PageBlock
  8. ToggleBlock
  9. BulletedBlock
  10. NumberedBlock
  11. QuoteBlock
  12. CalloutBlock
  13. LatexBlock
  14. TextBlock
  15. ImageBlock
  16. TableOfContentsBlock and
  17. LinkBlock If you want to create a collection, utilize the create_collection method [defined below].

To create a new block, you have a few options:

Create a block whose parent is the page

If you want to create a new block whose parent ID is the page, call the create method on the PageBlock instance.

  1. @page.create("<type_of_block", "title of block") → create a new block at the end of the page.
>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
>>> @page.create(NotionAPI::TextBlock, "Hiya!")
#<NotionAPI::TextBlock:0x00007fecd4459770 **omitted**>
  1. @page.create("<type_of_block", "title of block", "target_block_id") → create a new block after the target block.
>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
>>> @page.create(NotionAPI::TextBlock, "Hiya!", "ee0a6531-44cd-439f-a68c-1bdccbebfc8a")
#<NotionAPI::TextBlock:0x00007fecd8859770 **omitted**>
  1. @page.create("<type_of_block"), "title of block", "target_block_id", "before/after") → create a new block after or before the target block.
>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
>>> @page.create(NotionAPI::TextBlock, "Hiya!", "ee0a6531-44cd-439f-a68c-1bdccbebfc8a", "before")
#<NotionAPI::TextBlock:0x00007fecd8859880 **omitted**>
  1. @page.create(<type_of_block>, "title of block", options: { emoji: "chosen emoji" }) → create a new block with a chosen emoji for blocks with emojis (PageBlock and CalloutBlock).
>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
>>> @page.create(NotionAPI::PageBlock, "Hiya!", options: { emoji: "🚀" })
#<NotionAPI::PageBlock:0x00007f80ed2abf78 **omitted**>
  1. @page.create(<type_of_block>, "title of block", options: { content: "text or markdown" }) → create a new block with text or markdown content.
>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
>>> @page.create(NotionAPI::PageBlock, "Hiya!", options: { content: "# Yippee Ki Yay\n\nJohn McClane" })
#<NotionAPI::PageBlock:0x00007fa77a1d0ca8 **omitted**>

Create a block whose parent is another block

If you want to create a nested block whose parent ID is another block, call the create method on that block.

  1. @block.create("<type_of_block", "title of block") → create a new nested block whose parent ID is @block.id
>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
>>> @block = @page.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
>>> @block.create(NotionAPI::TextBlock, "Hiya!") # create a nested text block
#<NotionAPI::TextBlock:0x00007fecd8861780 **omitted**>
  1. @block.create("<type_of_block", "title of block", "target_block") → create a new nested block whose parent ID is @block.id and whose location is after the target block
>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
>>> @block = @page.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
>>> @block.create(NotionAPI::TextBlock, "Hiya!" "ae3d1c60-b9d1-0ac0-0fff-16d3fc8907a2") # create a nested text block after a specific child
#<NotionAPI::TextBlock:0x00007fecd8859781 **omitted**>
  1. @block.create("<type_of_block", "title of block", "target_block", "before/after") → reate a new nested block whose parent ID is @block.id and whose location is before the target block
>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
>>> @block = @page.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
>>> @block.create(NotionAPI::TextBlock, "Hiya!" "ae3d1c60-b9d1-0ac0-0fff-16d3fc8907a2", "before") # create a nested text block before a specific child
#<NotionAPI::TextBlock:0x00007fecd8859781 **omitted**>

The simplest way to describe this: the parent ID of the created block is the ID of the block the create method is invoked on. If the create method is invoked on a PageBlock, the block is a child of that page. If the create method is invoked on a block within the page, the block is a child of that block.

** NOTE: Notion only supports 'nesting' certain block types. If you try to nest a block that cannot be nested, it will fail. **

Creating New Collections

Let's say we have the following JSON data:

[
  {
    "emoji": "😀",
    "description": "grinning face",
    "category": "Smileys & Emotion",
    "aliases": ["grinning"],
    "tags": ["smile", "happy"],
    "unicode_version": "6.1",
    "ios_version": "6.0"
  },
  {
    "emoji": "😃",
    "description": "grinning face with big eyes",
    "category": "Smileys & Emotion",
    "aliases": ["smiley"],
    "tags": ["happy", "joy", "haha"],
    "unicode_version": "6.0",
    "ios_version": "6.0"
  }
]

A new table collection view containing this data is created with the following code:

>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
>>> @page.create_collection("table", "title for table", JSON.parse(File.read("./path/to/emoji_json_data.json")))

Here's an example with a larger dataset: create a collection view table

Additionally, say you already have a Table and want to add a new row with it containing the following data:

{
    "emoji": "😉",
    "description": "winking face",
    "category": "Smileys & Emotion",
    "aliases": ["wink"],
    "tags": ["flirt"],
    "unicode_version": "6.0",
    "ios_version": "6.0"
}
>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
>>> @collection = @page.get_collection("f1664a99-165b-49cc-811c-84f37655908a")
>>> @collection.add_row(JSON.parse(File.read("path/to/new_emoji_row.json")))

The first argument passed to create_collection determines which type of collection view to create. In the above example, a "table" is created, but other supported options are:

  1. list
  2. board
  3. calendar
  4. timeline
  5. gallery

Updating Collection View Cells

When you retrieve a CollectionViewRow instance with .row(<row_id>) or a list of CollectionViewRow instances with .rows, a handful of methods are created. Each row instance has access attributes that represent the properties in the Notion Collection View. So, let's say we are working with the following Notion Collection View:

emoji description category aliases tags unicode_version ios_version
😉 "winking face" "Smileys & Emotion" "wink" "flirt" "6.0" "6.0"

If you wanted to update the unicode and ios versions, you could use the following code:

>>> collection_view = @page.get_collection("1234567") # the ID of the collection block is 1234567
>>> rows = collection_view.rows
>>> row[0].unicode_version = "updated version here!"
>>> row[0].ios_version = "I was updated too!"

Now, your Collection View will look like this:

emoji description category aliases tags unicode_version ios_version
😉 "winking face" "Smileys & Emotion" "wink" "flirt" "updated version here!" "I was updated too!"

You can also add new rows with the .add_row({<data!>}) method and add new properties with the .add_property("name_of_property", "type_of_property") method.

One important thing to be aware of: When adding a row with .add_row, the hash of data passed must be in the same order as it appears in your Notion Collection View.

Troubleshooting

No results returned when attempting to get a page

If an empty hash is returned when you attempt to retrieve a Notion page, you'll need to include the x-notion-active-user-header when instantiating the Notion Client. The endpoint used by this wrapper to load a page is /loadPageChunk, check out the request headers in your developer tools Network tab.

From here, you can instantiate the Notion Client with the following code:

>>> @client = NotionAPI::Client.new(
  "<insert_v2_token_here>",
  "<insert_x_notion_active_user_header_here>"
)

Retrieve a full-page Collection View

A full-page collection view must have a URL that follows the below pattern: https://www.notion.so/danmurphy/[page-id]?v=[view-id] Then, it can be retrieved with the following code:

>>> @client = NotionAPI::Client.new(
  "<insert_v2_token_here>"
)
>>> @client.get_page("https://www.notion.so/danmurphy/[page-id]?v=[view-id]")

Linking to another page

You can create a block that links to another notion page with the following syntax:

@client = NotionAPI::Client.new(ENV["token_v2"])
@page = @client.get_page("https://www.notion.so/danmurphy/Testing-227581d35fc94fa1a5f9fda1e8478d1e")
@page.create(NotionAPI::LinkBlock, "ea93213d1f21439c870fbe91503e76fe")

This example will create a LinkBlock on the Testing page to the page with ID ea93213d1f21439c870fbe91503e76fe.

notion-ruby's People

Contributors

codacy-badger avatar danmurphy1217 avatar nfilzi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

notion-ruby's Issues

add_row doesn't seem to work

Hey there! Thanks for this gem. I just gave it a shot and unfortunately it seems like add_row doesn't really work. I'm getting a response from Notion with PostgresNullConstraintError. I have a basic collection with Name property and I do:

page.add_row(Name: "Test")

I tried with different collections and different property names (ie "Title" or "title" but nothing works).

Am I doing something wrong or is it a bug?

Crashes when property is a self-ref relation

If you have a property that is a relation to itself, then the following exception is raised:

NameError: `@related_to_tasks_(parent)' is not allowed as an instance variable name

Failed to run method get_page

I installed the gem, and put this code into my seed file

require 'notion_api'
@client = NotionAPI::Client.new("...")
@page = @client.get_page("05624583c9f442dfa8413368a23ed869")

but when I run the file I get the error
the URL or ID passed to the get_page method must be that of a Page Block.
even though the token is correct, anf the page ID was copied directly from the view

Link block

Hey @danmurphy1217, thanks so much for your work on this gem! Do you have plans to add link blocks? If not, I can fork and try to add.

`x-notion-active-user-header` not handed down to page block

When attempting to use page.children, or page.get_block('<BLOCK_ID>'), I get empty results back.

I believe I tracked down the bug to this part:

# notion-ruby/lib/notion_api/core.rb:139
def get_all_block_info(_clean_id, body)
      # ! retrieves all info pertaining to a block Id.
      # ! clean_id -> the block ID or URL cleaned : ``str``
      Core.options['cookies'][:token_v2] = @@token_v2
      Core.options['headers']['x-notion-active-user-header'] = @active_user_header # <--- 🚨
      cookies = Core.options['cookies']
      headers = Core.options['headers']
# [...]

When pry-byebugging it, I get nil when checking up @active_user_header, and the correct header value when checking up @@active_user_header.
I made the replacement in the source code installed on my system, and it looks like it fixed the issue.

What do you think?

Error when trying to write

Every time I try to write or do anything else than just reading Blocks terminal tells me that the method I'm trying to use doesn't exist. I have no Idea how to fix this, pls help! I'm quiet shit at coding though..

3.0.0 :095 > @page.title
 => "Telegram Test" 
3.0.0 :096"> @page.title = "hey!"
Traceback (most recent call last):
        4: from /Users/eumel/.rvm/rubies/ruby-3.0.0/bin/irb:23:in `<main>'
        3: from /Users/eumel/.rvm/rubies/ruby-3.0.0/bin/irb:23:in `load'
        2: from /Users/eumel/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.0/exe/irb:11:in `<top (required)>'
        1: from (irb):96:in `<main>'
NoMethodError (undefined method `title=' for #<NotionAPI::CollectionViewPage:0x00007ff141146308 @id="97967408-8a83-406c-8afe-32a1879ec3f4", @title="Telegram Test", @parent_id="bee0d234-4086-483d-9b1e-e1706ffccf5a", @collection_id="6cf1d6bf-a38d-433a-b203-330e3ab48337", @view_id="66f62fd8-86f9-4141-987a-767763fff159", @column_names=["Tags", "Name"]>)
Did you mean?  title
3.0.0 :097 > 

Error in extract_collection_schema method

I am trying to add a column with the add_property method but it returns an error.
I am getting the same error when I call rows on collection.

irb(main):004:0> notion_page.add_property('TEST', 'url')
Traceback (most recent call last):
        2: from (irb):3
        1: from (irb):4:in `rescue in irb_binding'
NoMethodError (undefined method `[]' for nil:NilClass)
irb(main):005:0>

Looks like POST request in extract_collection_schema is invalid, it is returning validation error.

response.body
"{\"errorId\":\"83f22b07-f9c5-4247-a2bf-96c20799a974\",\"name\":\"ValidationError\",\"message\":\"Invalid input.\"}"

Adding images doesn't work

Adding images doesn't work (By URL and with source file)

@page.create(NotionAPI::ImageBlock, file_url)

just creates an empty image block

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.