Favicon

Page query in database

Peponi1/23/202514m

C#
NotionDatabaseHttpPostGetPatchJson

1. Introduction

Notion은 페이지, 데이터베이스 등에 대해 REST API를 지원한다.

여기서는 database에 대한 page 작업을 다룬다.

  1. Create a page
  2. Retrieve a page
  3. Update page properties
  4. Archive a page

2. Database to perform

Page query 방법에 앞서, 테스트를 수행할 DB의 형태는 아래와 같다.

databaseImage

DB 작업 수행 간 JSON 형식의 Page object를 HTTP body에 실어 전송받게 된다. Reference 페이지를 참조하여 구현한 JSON object의 형태는 아래와 같다.

QueryPageItem (펼치기 / 접기)
using System.Text.Json.Serialization;
 
namespace NotionAPI.Objects;
 
// https://developers.notion.com/reference/post-page 에 따라 작성
public class QueryPageItem
{
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public Parent? parent { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public Dictionary<string, PageProperty>? properties { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public List<object>? children { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public object? icon { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public object? cover { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public bool? archived { get; set; }
}
PageInformation (펼치기 / 접기)
using System.Text.Json.Serialization;
 
namespace NotionAPI.Objects;
 
// https://developers.notion.com/reference/page 에 따라 작성
public class PageInformation
{
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? @object { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? id { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public DateTime created_time { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public User? created_by { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public DateTime last_edited_time { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public User? last_edited_by { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public bool archived { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public object? icon { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public object? cover { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public Dictionary<string, PageProperty>? properties { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public Parent? parent { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? url { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? public_url { get; set; }
}
PageProperty (펼치기 / 접기)
using System.Text.Json;
using System.Text.Json.Serialization;
 
namespace NotionAPI.Objects;
 
// https://developers.notion.com/reference/page-property-values 에 따라 작성
[JsonConverter(typeof(PagePropertyConverter))]
public class PageProperty
{
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? id { get; set; }
}
 
public sealed class PageSelect : PageProperty
{
    public Select? select { get; set; }
}
 
public sealed class PageTitle : PageProperty
{
    public List<RichText>? title { get; set; }
}
 
public class PagePropertyConverter : JsonConverter<PageProperty>
{
    public override PageProperty? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var jsonDoc = JsonDocument.ParseValue(ref reader);
        if (jsonDoc.RootElement.TryGetProperty("type", out var typeName))
        {
            return typeName.GetString() switch
            {
                "select" => JsonSerializer.Deserialize<PageSelect>(jsonDoc),
                "title" => JsonSerializer.Deserialize<PageTitle>(jsonDoc),
                _ => null
            };
        }
 
        return null;
    }
 
    public override void Write(Utf8JsonWriter writer, PageProperty value, JsonSerializerOptions options)
    {
        switch (value)
        {
            case PageSelect select:
                JsonSerializer.Serialize(writer, select);
                break;
 
            case PageTitle title:
                JsonSerializer.Serialize(writer, title);
                break;
        }
    }
}
User (펼치기 / 접기)
using System.Text.Json.Serialization;
 
namespace NotionAPI.Objects;
 
// https://developers.notion.com/reference/user 에 따라 작성
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(People), typeDiscriminator: "person")]
[JsonDerivedType(typeof(Bots), typeDiscriminator: "bot")]
public class User
{
    public string? @object { get; set; }
    public string? id { get; set; }
    public string? name { get; set; }
    public string? avatar_url { get; set; }
}
 
public sealed class People : User
{
    public object? person { get; set; }
}
 
public sealed class Bots : User
{
    public object? bot { get; set; }
}
Parent (펼치기 / 접기)
using System.Text.Json.Serialization;
 
namespace NotionAPI.Objects;
 
// https://developers.notion.com/reference/parent-object 에 따라 작성
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(DatabaseParent), typeDiscriminator: "database_id")]
[JsonDerivedType(typeof(PageParent), typeDiscriminator: "page_id")]
[JsonDerivedType(typeof(WorkspaceParent), typeDiscriminator: "workspace")]
[JsonDerivedType(typeof(BlockParent), typeDiscriminator: "block_id")]
public class Parent
{
}
 
public sealed class DatabaseParent : Parent
{
    public string? database_id { get; set; }
}
 
public sealed class PageParent : Parent
{
    public string? page_id { get; set; }
}
 
public sealed class WorkspaceParent : Parent
{
    public bool workspace { get; set; } = true;
}
 
public sealed class BlockParent : Parent
{
    public string? block_id { get; set; }
}
RichText (펼치기 / 접기)
using System.Text.Json.Serialization;
 
namespace NotionAPI.Objects;
 
// https://developers.notion.com/reference/rich-text 에 따라 작성
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(RichTextWithText), typeDiscriminator: "text")]
[JsonDerivedType(typeof(RichTextWithMention), typeDiscriminator: "mention")]
[JsonDerivedType(typeof(RichTextWithEquation), typeDiscriminator: "equation")]
public class RichText
{
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public Annotations? annotations { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? plain_text { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? href { get; set; }
}
 
public sealed class RichTextWithText : RichText
{
    public Text? text { get; set; }
}
 
public sealed class RichTextWithMention : RichText
{
    public object? mention { get; set; }
}
 
public sealed class RichTextWithEquation : RichText
{
    public object? equation { get; set; }
}
 
public class Annotations
{
    public bool bold { get; set; }
    public bool italic { get; set; }
    public bool strikethrough { get; set; }
    public bool underline { get; set; }
    public bool code { get; set; }
    public string? color { get; set; } = "default";
}
 
public class Text
{
    public string? content { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public Link? link { get; set; }
}
 
public class Link
{
    public string? url { get; set; }
}
Select (펼치기 / 접기)
using System.Text.Json.Serialization;
 
namespace NotionAPI.Objects;
 
// https://developers.notion.com/reference/property-object#select 에 따라 작성
public class Select
{
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? id { get; set; }
 
    public string? name { get; set; }
 
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? color { get; set; }
}

3. Create a page

DB에 새 페이지를 추가하는 방법은 아래와 같다.

using NotionAPI.Objects;
using System.Net.Http.Json;
using System.Text.Json;
 
private static void Main(string[] args)
{
    string baseUri = $"https://api.notion.com/v1/pages";
    string databaseKey = "데이터베이스 키";
    string APIKey = "API 키";
 
    Create(baseUri, databaseKey, APIKey);
}
 
private static bool Create(string baseUri, string databaseKey, string APIKey)
{
    HttpClient client = new();
 
    // https://developers.notion.com/reference/post-page 문서 내용에 따라 Post로 request 작성
    var request = new HttpRequestMessage(HttpMethod.Post, $"{baseUri}");
    request.Headers.Add("Authorization", $"Bearer {APIKey}");
    request.Headers.Add("Notion-Version", "2022-06-28");
 
    var queryItem = new QueryPageItem();
    queryItem.parent = new DatabaseParent() { database_id = databaseKey };
 
    var properties = new Dictionary<string, PageProperty>
    {
        { "이름", new PageTitle() { title = [new RichTextWithText() { text = new() { content = "5" } }] } },
        { "선택", new PageSelect() { select = new() { name = "2" } } }
    };
 
    queryItem.properties = properties;
    request.Content = JsonContent.Create(queryItem);
 
    var response = client.Send(request);
 
    // StatusCode를 포함한 Header 출력
    Console.WriteLine(response);
 
    // JSON 형식의 Body 출력
    var content = new StreamReader(response.Content.ReadAsStream()).ReadToEnd();
    Console.WriteLine(content);
 
    // Parsing
    var parsed = JsonSerializer.Deserialize<PageInformation>(content);
    Console.WriteLine($"Page key : {parsed?.id}");
 
    return response.StatusCode == System.Net.HttpStatusCode.OK;
}

정상적으로 페이지가 추가된 경우 아래 이미지와 같이 UI에 표시된다.

databaseAfter

수신되는 데이터는 아래와 같다.

Header (펼치기 / 접기)
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
    Date: Thu, 11 Apr 2024 23:03:08 GMT
    Connection: keep-alive
    X-Powered-By: Express
    x-notion-request-id: 79425409-d6c4-4f7e-af46-c4fcf9b1d7fd
    ETag: W/"3a1-FH+l03dxu3kIA70Ha6M4x4zVZ1Q"
    Vary: Accept-Encoding
    CF-Cache-Status: DYNAMIC
    Set-Cookie: __cf_bm=db7NUVgzSpxFIGnabQKSx8uKGVWP4sdzbSIrAgEpUMc-1712876588-1.0.1.1-ncsWrdfTHvjv7PNpeP4jU9BKfgwbbxk4PwOKWWn8er1QkthqzlKeEJMr_PVJET.H2d49DLFKaDG680qkRsS1jg; path=/; expires=Thu, 11-Apr-24 23:33:08 GMT; domain=.notion.com; HttpOnly; Secure
    Server: cloudflare
    CF-RAY: 872e9bb22f71329c-ICN
    Content-Type: application/json; charset=utf-8
    Content-Length: 929
}
Body (펼치기 / 접기)
{
  "object": "page",
  "id": "Page id",
  "created_time": "2024-04-11T23:03:00.000Z",
  "last_edited_time": "2024-04-11T23:03:00.000Z",
  "created_by": {
    "object": "user",
    "id": "유저 id"
  },
  "last_edited_by": {
    "object": "user",
    "id": "유저 id"
  },
  "cover": null,
  "icon": null,
  "parent": {
    "type": "database_id",
    "database_id": "DB id"
  },
  "archived": false,
  "in_trash": false,
  "properties": {
    "선택": {
      "id": "sKnP",
      "type": "select",
      "select": {
        "id": "CsLi",
        "name": "2",
        "color": "gray"
      }
    },
    "이름": {
      "id": "title",
      "type": "title",
      "title": [
        {
          "type": "text",
          "text": {
            "content": "5",
            "link": null
          },
          "annotations": {
            "bold": false,
            "italic": false,
            "strikethrough": false,
            "underline": false,
            "code": false,
            "color": "default"
          },
          "plain_text": "5",
          "href": null
        }
      ]
    }
  },
  "url": "https://www.notion.so/5-Page id",
  "public_url": null,
  "request_id": "79425409-d6c4-4f7e-af46-c4fcf9b1d7fd"
}

4. Retrieve a page

Page의 id를 알고 있다면 해당 page의 정보를 얻어올 수 있다.

using NotionAPI.Objects;
using System.Text.Json;
 
private static void Main(string[] args)
{
    string baseUri = $"https://api.notion.com/v1/pages";
    string pageKey = "Page 키";
    string APIKey = "API 키";
 
    Console.WriteLine(Retrieve(baseUri, pageKey, APIKey));
}
 
private static bool Retrieve(string baseUri, string pageKey, string APIKey)
{
    HttpClient client = new();
 
    // https://developers.notion.com/reference/retrieve-a-page 문서 내용에 따라 Get으로 request 작성
    var request = new HttpRequestMessage(HttpMethod.Get, $"{baseUri}/{pageKey}");
    request.Headers.Add("Authorization", $"Bearer {APIKey}");
    request.Headers.Add("Notion-Version", "2022-06-28");
 
    var response = client.Send(request);
 
    // StatusCode를 포함한 Header 출력
    Console.WriteLine(response);
 
    // JSON 형식의 Body 출력
    var content = new StreamReader(response.Content.ReadAsStream()).ReadToEnd();
    Console.WriteLine(content);
 
    var parsed = JsonSerializer.Deserialize<PageInformation>(content);
 
    return response.StatusCode == System.Net.HttpStatusCode.OK;
}

수신되는 데이터는 아래와 같다.

Header (펼치기 / 접기)
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
    Date: Thu, 11 Apr 2024 23:09:09 GMT
    Connection: keep-alive
    X-Powered-By: Express
    x-notion-request-id: b3ca9a32-2a2d-4e98-9198-a97d71c82434
    ETag: W/"3a1-VH41nGESWpRWFLu2jXoGdY84fSU"
    Vary: Accept-Encoding
    CF-Cache-Status: DYNAMIC
    Set-Cookie: __cf_bm=JEsgOya342GIBSYbtCzwFBr7m.gOIiJF4w5rrrvnNnI-1712876949-1.0.1.1-aJ2d3dMM99HohpAwBh1A99GRK61AnfsFJ1nCeYw66lEEGqXVROXceGAWwl3GqZaseV0ghn0wSd.iQ8QputNZyg; path=/; expires=Thu, 11-Apr-24 23:39:09 GMT; domain=.notion.com; HttpOnly; Secure
    Server: cloudflare
    CF-RAY: 872ea4833956c071-ICN
    Content-Type: application/json; charset=utf-8
    Content-Length: 929
}
Body (펼치기 / 접기)
{
  "object": "page",
  "id": "Page id",
  "created_time": "2024-04-11T23:03:00.000Z",
  "last_edited_time": "2024-04-11T23:03:00.000Z",
  "created_by": {
    "object": "user",
    "id": "유저 id"
  },
  "last_edited_by": {
    "object": "user",
    "id": "유저 id"
  },
  "cover": null,
  "icon": null,
  "parent": {
    "type": "database_id",
    "database_id": "DB id"
  },
  "archived": false,
  "in_trash": false,
  "properties": {
    "선택": {
      "id": "sKnP",
      "type": "select",
      "select": {
        "id": "CsLi",
        "name": "2",
        "color": "gray"
      }
    },
    "이름": {
      "id": "title",
      "type": "title",
      "title": [
        {
          "type": "text",
          "text": {
            "content": "5",
            "link": null
          },
          "annotations": {
            "bold": false,
            "italic": false,
            "strikethrough": false,
            "underline": false,
            "code": false,
            "color": "default"
          },
          "plain_text": "5",
          "href": null
        }
      ]
    }
  },
  "url": "https://www.notion.so/5-Page id",
  "public_url": null,
  "request_id": "b3ca9a32-2a2d-4e98-9198-a97d71c82434"
}

5. Update page properties

PATCH request를 통해 page의 속성을 변경할 수 있다. 이 때 변경할 속성을 body에 실어 보낸다.

using NotionAPI.Objects;
using System.Net.Http.Json;
using System.Text.Json;
 
private static void Main(string[] args)
{
    string baseUri = $"https://api.notion.com/v1/pages";
    string pageKey = "Page 키";
    string APIKey = "API 키";
 
    Update(baseUri, pageKey, APIKey);
}
 
private static bool Update(string baseUri, string pageKey, string APIKey)
{
    HttpClient client = new();
 
    // https://developers.notion.com/reference/patch-page 문서 내용에 따라 Patch로 request 작성
    var request = new HttpRequestMessage(HttpMethod.Patch, $"{baseUri}/{pageKey}");
    request.Headers.Add("Authorization", $"Bearer {APIKey}");
    request.Headers.Add("Notion-Version", "2022-06-28");
 
    var queryItem = new QueryPageItem();
 
    var properties = new Dictionary<string, PageProperty>()
    {
        { "선택" , new PageSelect() { select = new() { name = "1" } } }
    };
 
    queryItem.properties = properties;
    request.Content = JsonContent.Create(queryItem);
 
    var response = client.Send(request);
 
    // StatusCode를 포함한 Header 출력
    Console.WriteLine(response);
 
    // JSON 형식의 Body 출력
    var content = new StreamReader(response.Content.ReadAsStream()).ReadToEnd();
    Console.WriteLine(content);
 
    var parsed = JsonSerializer.Deserialize<PageInformation>(content);
 
    return response.StatusCode == System.Net.HttpStatusCode.OK;
}

정상적으로 업데이트가 수행되면 아래 이미지와 같이 UI에 표시된다.

databaseUpdate

수신되는 데이터는 아래와 같다.

Header (펼치기 / 접기)
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
    Date: Thu, 11 Apr 2024 23:25:12 GMT
    Connection: keep-alive
    X-Powered-By: Express
    x-notion-request-id: e9860a05-57ad-4af3-840a-9131d1a63a14
    ETag: W/"3a3-1n/Ro8ikDAsBoSwv2px7Hn0qHOM"
    Vary: Accept-Encoding
    CF-Cache-Status: DYNAMIC
    Set-Cookie: __cf_bm=CPbn0HafswMCKjwPy0KcFkRS9acC84..kK1qKaFfMDA-1712877912-1.0.1.1-nts9GcwFNiFeWgx6.__DrUgd2QsvGXSsA4r2oivFQd5GZcHQcCWcj.8loYqKvG.JL3xxdUUXpuV4FKbWfgac4w; path=/; expires=Thu, 11-Apr-24 23:55:12 GMT; domain=.notion.com; HttpOnly; Secure
    Server: cloudflare
    CF-RAY: 872ebc081c9bc17d-ICN
    Content-Type: application/json; charset=utf-8
    Content-Length: 931
}
Body (펼치기 / 접기)
{
  "object": "page",
  "id": "Page id",
  "created_time": "2024-04-11T23:03:00.000Z",
  "last_edited_time": "2024-04-11T23:25:00.000Z",
  "created_by": {
    "object": "user",
    "id": "유저 id"
  },
  "last_edited_by": {
    "object": "user",
    "id": "유저 id"
  },
  "cover": null,
  "icon": null,
  "parent": {
    "type": "database_id",
    "database_id": "DB id"
  },
  "archived": false,
  "in_trash": false,
  "properties": {
    "선택": {
      "id": "sKnP",
      "type": "select",
      "select": {
        "id": "@:oT",
        "name": "1",
        "color": "yellow"
      }
    },
    "이름": {
      "id": "title",
      "type": "title",
      "title": [
        {
          "type": "text",
          "text": {
            "content": "5",
            "link": null
          },
          "annotations": {
            "bold": false,
            "italic": false,
            "strikethrough": false,
            "underline": false,
            "code": false,
            "color": "default"
          },
          "plain_text": "5",
          "href": null
        }
      ]
    }
  },
  "url": "https://www.notion.so/5-Page id",
  "public_url": null,
  "request_id": "e9860a05-57ad-4af3-840a-9131d1a63a14"
}

6. Archive a page

Notion API는 page의 영구 삭제를 지원하지 않는 대신 보관 기능을 지원하며 UI에서 숨김 처리가 된다. Body의 archived 속성을 true로 설정하면 보관, false로 설정하면 해제가 된다. 아래는 true로 설정하여 보관하는 예시를 보여준다.

using NotionAPI.Objects;
using System.Net.Http.Json;
 
private static void Main(string[] args)
{
    string baseUri = $"https://api.notion.com/v1/pages";
    string pageKey = "Page 키";
    string APIKey = "API 키";
 
    Archieve(baseUri, pageKey, APIKey);
}
 
private static bool Archieve(string baseUri, string pageKey, string APIKey)
{
    HttpClient client = new();
 
    // https://developers.notion.com/reference/archive-a-page 문서 내용에 따라 Patch로 request 작성
    var request = new HttpRequestMessage(HttpMethod.Patch, $"{baseUri}/{pageKey}");
    request.Headers.Add("Authorization", $"Bearer {APIKey}");
    request.Headers.Add("Notion-Version", "2022-06-28");
 
    var queryItem = new QueryPageItem();
    queryItem.archived = true;
    request.Content = JsonContent.Create(queryItem);
 
    var response = client.Send(request);
 
    // StatusCode를 포함한 Header 출력
    Console.WriteLine(response);
 
    // JSON 형식의 Body 출력
    Console.WriteLine(new StreamReader(response.Content.ReadAsStream()).ReadToEnd());
 
    return response.StatusCode == System.Net.HttpStatusCode.OK;
}

정상적으로 기능이 수행되었다면 UI에서 항목이 사라진다.

databaseArchieve

수신되는 데이터는 아래와 같다.

Header (펼치기 / 접기)
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
    Date: Thu, 11 Apr 2024 23:33:54 GMT
    Connection: keep-alive
    X-Powered-By: Express
    x-notion-request-id: 121f6b11-1c42-4f4f-9171-1eea30a2c5ac
    ETag: W/"3a1-TL1xmU1SdWnUsVY+g5AIC/QdNmU"
    Vary: Accept-Encoding
    CF-Cache-Status: DYNAMIC
    Set-Cookie: __cf_bm=_lT094_241halWvRUhfWo9HJyKUIzPo9HezNiGr1kfo-1712878434-1.0.1.1-qgv6Tzj9Whr9x7dXz7M53J3dkIU3VDiSMeHwfTScycdRndYTxuG0Bq9Q.gqxNVpqA1Yf_puzTUvDf6rzSNqn8w; path=/; expires=Fri, 12-Apr-24 00:03:54 GMT; domain=.notion.com; HttpOnly; Secure
    Server: cloudflare
    CF-RAY: 872ec8c8d89ac067-ICN
    Content-Type: application/json; charset=utf-8
    Content-Length: 929
}
Body (펼치기 / 접기)
{
  "object": "page",
  "id": "Page id",
  "created_time": "2024-04-11T23:03:00.000Z",
  "last_edited_time": "2024-04-11T23:33:00.000Z",
  "created_by": {
    "object": "user",
    "id": "유저 id"
  },
  "last_edited_by": {
    "object": "user",
    "id": "유저 id"
  },
  "cover": null,
  "icon": null,
  "parent": {
    "type": "database_id",
    "database_id": "DB id"
  },
  "archived": true,
  "in_trash": true,
  "properties": {
    "선택": {
      "id": "sKnP",
      "type": "select",
      "select": {
        "id": "@:oT",
        "name": "1",
        "color": "yellow"
      }
    },
    "이름": {
      "id": "title",
      "type": "title",
      "title": [
        {
          "type": "text",
          "text": {
            "content": "5",
            "link": null
          },
          "annotations": {
            "bold": false,
            "italic": false,
            "strikethrough": false,
            "underline": false,
            "code": false,
            "color": "default"
          },
          "plain_text": "5",
          "href": null
        }
      ]
    }
  },
  "url": "https://www.notion.so/5-Page id",
  "public_url": null,
  "request_id": "121f6b11-1c42-4f4f-9171-1eea30a2c5ac"
}

7. 참조 자료