Skip to content
On this page

2020-11-17

Title
2020-11-17
Category
2020
Tags
Aliases
2020-11-17
Created
3 years ago
Updated
last year

Narkdown 프로젝트

  • notion-py 를 사용해서 Python 기반으로진행했었지만 Python을 잘 사용하지 않다보니 유지 보수하기 힘들었다.

  • ts 기반 notion-api-worker 가 있어서 이를 사용하려고 한다.

목표

  • CLI로 page url 또는 database url을 입력 받고 notion의 컨텐츠를 파싱하여 md 파일을 생성하자. (CMS를 위해)

  • 이후 웹 페이지를 만들 수 있으면 좋을 듯.

fetch vs axios

프론트엔드에서 fetch, axios는 자주 사용했는데, node 환경에서 api 요청을 해보는것은 처음이라, 어떤 것을 사용할지 고민했다.

  • axios는 node 환경에서도 동일하게 사용하는 것이 가능하다.

  • fetch는 node-fetch 라는 라이브러리를 사용해야 한다. 이 라이브러리는 NodeJS 런타임 환경에서 window.fetch 를 사용하기 위한 최소한의 코드를 목표로 한다고 한다.

  • 프론트엔드 환경에서 fetch 가 라이브러리 설치 없이 사용할 수 있는게 장점이라고생각하는데, 굳이 node-fetch를 사용할 필요는 없을 것 같아서, axios를 사용하기로결정했다. (보안적인 옵션도 axios가 많이 제공한다.)

https://www.geeksforgeeks.org/difference-between-fetch-and-axios-js-for-making-http-requests/

ts-node

  • tsconfig 생성 명령어
bash
tsc --init
tsc --init
  • tsconfig 옵션 정리

8 Best Practices for Future-Proofing Your TypeScript Code

tsconfig 컴파일 옵션 정리

[TS / Node] TS + Node.js + Express + Babel(option) + eslint로 개발환경 세팅하기

Node.js 시작하기

notion-api-worker

  • get page 리턴

    • 기본 페이지
      json
      {
      	"847c0e9b-15a1-42c9-9392-ca2f817c4eac": {
      		"role": "editor",
      		"value": {
      			"id": "847c0e9b-15a1-42c9-9392-ca2f817c4eac",
      			"version": 23,
      			"type": "page",
      			"properties": {
      				"title": [["hello"]]
      			},
      			"content": ["cc1dee2e-269d-4cd0-a5a3-b1c3d72edf61"],
      			"permissions": [
      				{
      					"role": "editor",
      					"type": "user_permission",
      					"user_id": "b21a69b3-a19b-438c-b599-e850190836a3"
      				}
      			],
      			"created": 1605604740000,
      			"last_edited_time": 1605604740000,
      			"parent_id": "ee7c0178-18cf-474e-a665-83f2432f545f",
      			"parent_table": "space",
      			"alive": true,
      			"created_by_table": "notion_user",
      			"created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"last_edited_by_table": "notion_user",
      			"last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"shard_id": 1004639,
      			"space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
      		}
      	},
      	"cc1dee2e-269d-4cd0-a5a3-b1c3d72edf61": {
      		"role": "editor",
      		"value": {
      			"id": "cc1dee2e-269d-4cd0-a5a3-b1c3d72edf61",
      			"version": 12,
      			"type": "text",
      			"properties": {
      				"title": [["1234"]]
      			},
      			"created": 1605604740000,
      			"last_edited_time": 1605604740000,
      			"parent_id": "847c0e9b-15a1-42c9-9392-ca2f817c4eac",
      			"parent_table": "block",
      			"alive": true,
      			"created_by_table": "notion_user",
      			"created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"last_edited_by_table": "notion_user",
      			"last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"shard_id": 1004639,
      			"space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
      		}
      	}
      }
      
      {
      	"847c0e9b-15a1-42c9-9392-ca2f817c4eac": {
      		"role": "editor",
      		"value": {
      			"id": "847c0e9b-15a1-42c9-9392-ca2f817c4eac",
      			"version": 23,
      			"type": "page",
      			"properties": {
      				"title": [["hello"]]
      			},
      			"content": ["cc1dee2e-269d-4cd0-a5a3-b1c3d72edf61"],
      			"permissions": [
      				{
      					"role": "editor",
      					"type": "user_permission",
      					"user_id": "b21a69b3-a19b-438c-b599-e850190836a3"
      				}
      			],
      			"created": 1605604740000,
      			"last_edited_time": 1605604740000,
      			"parent_id": "ee7c0178-18cf-474e-a665-83f2432f545f",
      			"parent_table": "space",
      			"alive": true,
      			"created_by_table": "notion_user",
      			"created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"last_edited_by_table": "notion_user",
      			"last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"shard_id": 1004639,
      			"space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
      		}
      	},
      	"cc1dee2e-269d-4cd0-a5a3-b1c3d72edf61": {
      		"role": "editor",
      		"value": {
      			"id": "cc1dee2e-269d-4cd0-a5a3-b1c3d72edf61",
      			"version": 12,
      			"type": "text",
      			"properties": {
      				"title": [["1234"]]
      			},
      			"created": 1605604740000,
      			"last_edited_time": 1605604740000,
      			"parent_id": "847c0e9b-15a1-42c9-9392-ca2f817c4eac",
      			"parent_table": "block",
      			"alive": true,
      			"created_by_table": "notion_user",
      			"created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"last_edited_by_table": "notion_user",
      			"last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"shard_id": 1004639,
      			"space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
      		}
      	}
      }
      
    • Database 하위 페이지
      json
      {
        "15afa14b-8f9c-4b6c-97cc-46375c775cc5": {
          "role": "reader",
          "value": {
            "id": "15afa14b-8f9c-4b6c-97cc-46375c775cc5",
            "version": 25,
            "type": "page",
            "properties": [Object],
            "created": 1605517260000,
            "last_edited_time": 1605602760000,
            // 부모 Id
            // 데이터베이스의 경우 collection_id
            "parent_id": "e543505f-be64-46cd-9c55-07117dc85a92",
            // 부모
            "parent_table": "collection",
            "alive": true,
            "created_by_table": "notion_user",
            // user_id
            "created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
            "last_edited_by_table": "notion_user",
            "last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
            "shard_id": 1004639,
            "space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
          }
        },
      
        // 부모가 space가 아닌 경우 부모
        "acc3dfd0-339e-4cac-b5ba-ae8673fddfad": {
          "role": "reader",
          "value": {
            "id": "acc3dfd0-339e-4cac-b5ba-ae8673fddfad",
            "version": 106,
            "type": "collection_view_page",
            "view_ids": [Array],
            "collection_id": "e543505f-be64-46cd-9c55-07117dc85a92",
            "format": [Object],
            "permissions": [Array],
            "created": 1600223639505,
            "last_edited_time": 1605594780000,
            "parent_id": "ee7c0178-18cf-474e-a665-83f2432f545f",
            "parent_table": "space",
            "alive": true,
            "created_by_table": "notion_user",
            "created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
            "last_edited_by_table": "notion_user",
            "last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
            "shard_id": 1004639,
            "space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
          }
        }
      }
      
      {
        "15afa14b-8f9c-4b6c-97cc-46375c775cc5": {
          "role": "reader",
          "value": {
            "id": "15afa14b-8f9c-4b6c-97cc-46375c775cc5",
            "version": 25,
            "type": "page",
            "properties": [Object],
            "created": 1605517260000,
            "last_edited_time": 1605602760000,
            // 부모 Id
            // 데이터베이스의 경우 collection_id
            "parent_id": "e543505f-be64-46cd-9c55-07117dc85a92",
            // 부모
            "parent_table": "collection",
            "alive": true,
            "created_by_table": "notion_user",
            // user_id
            "created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
            "last_edited_by_table": "notion_user",
            "last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
            "shard_id": 1004639,
            "space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
          }
        },
      
        // 부모가 space가 아닌 경우 부모
        "acc3dfd0-339e-4cac-b5ba-ae8673fddfad": {
          "role": "reader",
          "value": {
            "id": "acc3dfd0-339e-4cac-b5ba-ae8673fddfad",
            "version": 106,
            "type": "collection_view_page",
            "view_ids": [Array],
            "collection_id": "e543505f-be64-46cd-9c55-07117dc85a92",
            "format": [Object],
            "permissions": [Array],
            "created": 1600223639505,
            "last_edited_time": 1605594780000,
            "parent_id": "ee7c0178-18cf-474e-a665-83f2432f545f",
            "parent_table": "space",
            "alive": true,
            "created_by_table": "notion_user",
            "created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
            "last_edited_by_table": "notion_user",
            "last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
            "shard_id": 1004639,
            "space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
          }
        }
      }
      
    • 메타데이터가 있는 페이지
      json
      {
      	"1c7c8eb6-ec3b-42fb-b950-63abd3c9bd61": {
      		"role": "reader",
      		"value": {
      			"id": "1c7c8eb6-ec3b-42fb-b950-63abd3c9bd61",
      			"version": 6,
      			"type": "page",
      			// 데이터베이스 하위에 있는 페이지의 메타데이터 부모 데이터베이스에 접근해서 가져와야 함.
      			"properties": {
      				"RXKJ": [
      					// 여러 태그 목록이 문자열 ',' 로 구분되어 옴.
      					["hello,bye"]
      				],
      				"fb_;": [["🛠 In Progress"]],
      				"qS^H": [["Test"]],
      				"title": [["asdf"], ["의 사본"]]
      			},
      			// 전체 페이지, 작은 페이지 사이즈일 때 함께 옴, 없으면 안옴.
      			"format": {
      				"page_icon": "🚡",
      				// link인 경우는 링크
      				"page_cover": "https://user-images.githubusercontent.com/1440854/79684011-6c948280-822e-11ea-9e23-1644903796fb.png",
      				// 업로드인 경우 https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d53a69fd-a3e1-4914-b014-63158a1078a2/blue.png
      				// 기본 제공인 경우 /images/blue.png => https://notion.so/images/blue.png로 접근 가능
      				"page_cover_position": 0.5,
      				"page_full_width": true,
      				"page_small_text": true
      			},
      			"created": 1605594821014,
      			"last_edited_time": 1605603000000,
      			"parent_id": "e543505f-be64-46cd-9c55-07117dc85a92",
      			"parent_table": "collection",
      			"alive": true,
      			"copied_from": "15afa14b-8f9c-4b6c-97cc-46375c775cc5",
      			"created_by_table": "notion_user",
      			"created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"last_edited_by_table": "notion_user",
      			"last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"shard_id": 1004639,
      			"space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
      		}
      	},
      	"acc3dfd0-339e-4cac-b5ba-ae8673fddfad": {
      		"role": "reader",
      		"value": {
      			"id": "acc3dfd0-339e-4cac-b5ba-ae8673fddfad",
      			"version": 106,
      			"type": "collection_view_page",
      			"view_ids": [
      				"be43c1c8-dd64-4cfb-9df9-efd97d8af60a",
      				"cfabb574-6051-47ed-9c14-ea3a1b6aead7",
      				"87cdd007-d8d6-464c-82f2-c7a4153bab0d",
      				"c09c2c36-0419-4bff-8195-bf6c2b897d6f",
      				"e0d39abd-4d7b-4c5c-9ce9-4984a3315932",
      				"83b3d2a6-6f63-4940-987d-1142e51da175"
      			],
      			"collection_id": "e543505f-be64-46cd-9c55-07117dc85a92",
      			"format": {
      				"page_cover_position": 0.6
      			},
      			"permissions": [
      				{
      					"role": "editor",
      					"type": "user_permission",
      					"user_id": "b21a69b3-a19b-438c-b599-e850190836a3"
      				},
      				{
      					"role": "reader",
      					"type": "public_permission"
      				}
      			],
      			"created": 1600223639505,
      			"last_edited_time": 1605594780000,
      			"parent_id": "ee7c0178-18cf-474e-a665-83f2432f545f",
      			"parent_table": "space",
      			"alive": true,
      			"created_by_table": "notion_user",
      			"created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"last_edited_by_table": "notion_user",
      			"last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"shard_id": 1004639,
      			"space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
      		}
      	}
      }
      
      {
      	"1c7c8eb6-ec3b-42fb-b950-63abd3c9bd61": {
      		"role": "reader",
      		"value": {
      			"id": "1c7c8eb6-ec3b-42fb-b950-63abd3c9bd61",
      			"version": 6,
      			"type": "page",
      			// 데이터베이스 하위에 있는 페이지의 메타데이터 부모 데이터베이스에 접근해서 가져와야 함.
      			"properties": {
      				"RXKJ": [
      					// 여러 태그 목록이 문자열 ',' 로 구분되어 옴.
      					["hello,bye"]
      				],
      				"fb_;": [["🛠 In Progress"]],
      				"qS^H": [["Test"]],
      				"title": [["asdf"], ["의 사본"]]
      			},
      			// 전체 페이지, 작은 페이지 사이즈일 때 함께 옴, 없으면 안옴.
      			"format": {
      				"page_icon": "🚡",
      				// link인 경우는 링크
      				"page_cover": "https://user-images.githubusercontent.com/1440854/79684011-6c948280-822e-11ea-9e23-1644903796fb.png",
      				// 업로드인 경우 https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d53a69fd-a3e1-4914-b014-63158a1078a2/blue.png
      				// 기본 제공인 경우 /images/blue.png => https://notion.so/images/blue.png로 접근 가능
      				"page_cover_position": 0.5,
      				"page_full_width": true,
      				"page_small_text": true
      			},
      			"created": 1605594821014,
      			"last_edited_time": 1605603000000,
      			"parent_id": "e543505f-be64-46cd-9c55-07117dc85a92",
      			"parent_table": "collection",
      			"alive": true,
      			"copied_from": "15afa14b-8f9c-4b6c-97cc-46375c775cc5",
      			"created_by_table": "notion_user",
      			"created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"last_edited_by_table": "notion_user",
      			"last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"shard_id": 1004639,
      			"space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
      		}
      	},
      	"acc3dfd0-339e-4cac-b5ba-ae8673fddfad": {
      		"role": "reader",
      		"value": {
      			"id": "acc3dfd0-339e-4cac-b5ba-ae8673fddfad",
      			"version": 106,
      			"type": "collection_view_page",
      			"view_ids": [
      				"be43c1c8-dd64-4cfb-9df9-efd97d8af60a",
      				"cfabb574-6051-47ed-9c14-ea3a1b6aead7",
      				"87cdd007-d8d6-464c-82f2-c7a4153bab0d",
      				"c09c2c36-0419-4bff-8195-bf6c2b897d6f",
      				"e0d39abd-4d7b-4c5c-9ce9-4984a3315932",
      				"83b3d2a6-6f63-4940-987d-1142e51da175"
      			],
      			"collection_id": "e543505f-be64-46cd-9c55-07117dc85a92",
      			"format": {
      				"page_cover_position": 0.6
      			},
      			"permissions": [
      				{
      					"role": "editor",
      					"type": "user_permission",
      					"user_id": "b21a69b3-a19b-438c-b599-e850190836a3"
      				},
      				{
      					"role": "reader",
      					"type": "public_permission"
      				}
      			],
      			"created": 1600223639505,
      			"last_edited_time": 1605594780000,
      			"parent_id": "ee7c0178-18cf-474e-a665-83f2432f545f",
      			"parent_table": "space",
      			"alive": true,
      			"created_by_table": "notion_user",
      			"created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"last_edited_by_table": "notion_user",
      			"last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",
      			"shard_id": 1004639,
      			"space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"
      		}
      	}
      }
      
  • get table 리턴

    • table로 된 페이지
      json
      [
      	{
      		"id": "11acfd54-2ee8-4640-b3fb-1782ce9b8caa",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Basic Blocks"
      	},
      	{
      		"id": "084bbefe-7f25-481a-bfbb-e8aff2152e4f",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Copy of Basic Blocks"
      	},
      	{
      		"id": "24786a8a-3d7d-4dfd-854d-ac40559c9f82",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Code Blocks"
      	},
      	{
      		"id": "74bbb810-9a68-499f-8f12-25dcce846f02",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Embed Blocks"
      	},
      	{
      		"id": "2df7176f-d58f-4c42-921b-55e9bbf0e92e",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Table Blocks"
      	},
      	{
      		"id": "30894478-96e6-4f95-9095-d84be27a82a9",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Page Blocks"
      	},
      	{
      		"id": "cee84696-242a-4f6e-953a-2c7ecb8b1603",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Advanced Blocks"
      	},
      	{
      		"id": "64c69eaf-268a-4076-bf48-d8ee5f2ca8c8",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Linked Page"
      	},
      	{
      		"id": "6a8383c0-0a12-4859-9edc-2fe41e9cbe75",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Recursive embed Image"
      	},
      	{
      		"id": "d10a7885-58f0-4ba9-b9a4-fb357ab796e8",
      		"Status": "🖨 Published",
      		"Category": "Example",
      		"Name": "Example Pages"
      	},
      	{
      		"id": "1c7c8eb6-ec3b-42fb-b950-63abd3c9bd61",
      		"Tags": ["hello", "bye"],
      		"Status": "🛠 In Progress",
      		"Category": "Test",
      		"Name": "asdf의 사본"
      	},
      	// 완전히 안지웠을 때는 빈문자열로 옴.
      	{
      		"id": "e8b450e4-f686-4d0b-9212-6241e6099a0b",
      		"Tags": [""],
      		"Status": "",
      		"Category": ""
      	}
      ]
      
      [
      	{
      		"id": "11acfd54-2ee8-4640-b3fb-1782ce9b8caa",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Basic Blocks"
      	},
      	{
      		"id": "084bbefe-7f25-481a-bfbb-e8aff2152e4f",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Copy of Basic Blocks"
      	},
      	{
      		"id": "24786a8a-3d7d-4dfd-854d-ac40559c9f82",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Code Blocks"
      	},
      	{
      		"id": "74bbb810-9a68-499f-8f12-25dcce846f02",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Embed Blocks"
      	},
      	{
      		"id": "2df7176f-d58f-4c42-921b-55e9bbf0e92e",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Table Blocks"
      	},
      	{
      		"id": "30894478-96e6-4f95-9095-d84be27a82a9",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Page Blocks"
      	},
      	{
      		"id": "cee84696-242a-4f6e-953a-2c7ecb8b1603",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Advanced Blocks"
      	},
      	{
      		"id": "64c69eaf-268a-4076-bf48-d8ee5f2ca8c8",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Linked Page"
      	},
      	{
      		"id": "6a8383c0-0a12-4859-9edc-2fe41e9cbe75",
      		"Status": "🖨 Published",
      		"Category": "Test",
      		"Name": "Recursive embed Image"
      	},
      	{
      		"id": "d10a7885-58f0-4ba9-b9a4-fb357ab796e8",
      		"Status": "🖨 Published",
      		"Category": "Example",
      		"Name": "Example Pages"
      	},
      	{
      		"id": "1c7c8eb6-ec3b-42fb-b950-63abd3c9bd61",
      		"Tags": ["hello", "bye"],
      		"Status": "🛠 In Progress",
      		"Category": "Test",
      		"Name": "asdf의 사본"
      	},
      	// 완전히 안지웠을 때는 빈문자열로 옴.
      	{
      		"id": "e8b450e4-f686-4d0b-9212-6241e6099a0b",
      		"Tags": [""],
      		"Status": "",
      		"Category": ""
      	}
      ]
      
  • blocks

Accept vs Content-Type

  • Accept : 클라이언트가 받을 수 있는 응답 형식을 지정함.

  • Content-Type : 클라이언트가 보내는 콘텐츠의 형식

Released under the MIT License.