소개

Notion의 DB를 API로 불러오는데 사용되는 코드입니다.
만약 해당DB에 특정 컬럼만 가져오고 싶다면 columnOrder를 사용하여 컬럼의 순서 및 이름을 지정할 수 있습니다.
ex) columnOrder = new List<string> { "Name", "Age", "Email" };

사용된 라이브러리는 Newtonsoft.Json,RestSharp 입니다.

using System.Data;
using Newtonsoft.Json.Linq;
using RestSharp;

   public class NotionAPI
   {
       private string _apiKey;
       private string _dbKey;

       public NotionAPI(string apiKey, string dbKey)
       {
           _apiKey = apiKey;
           _dbKey = dbKey;
       }

       /// <summary>
       /// Notion API에서 데이터를 가져와 DataTable로 반환합니다.
       /// </summary>
       /// <returns>DataTable 형태의 노션 데이터</returns>
       public async Task<DataTable> FetchDataAsDataTableAsync()
       {
           string jsonData = await FetchNotionDataAsync();
           return ParseDataToDataTable(jsonData);
       }

       public async Task<DataTable> FetchDataAsDataTableAsync(List<string> columnOrder = null)
       {
           string jsonData = await FetchNotionDataAsync();
           return ParseDataToDataTable(jsonData, columnOrder);
       }


       /// <summary>
       /// Notion API에서 데이터를 가져와 List<Dictionary<string, string>>로 반환합니다.
       /// </summary>
       /// <returns>List<Dictionary<string, string>> 형태의 노션 데이터</returns>
       public async Task<List<Dictionary<string, string>>> FetchDataAsListAsync()
       {
           string jsonData = await FetchNotionDataAsync();
           return ParseDataToList(jsonData);
       }

       public async Task<List<Dictionary<string, string>>> FetchDataAsListAsync(List<string> columnOrder = null)
       {
           string jsonData = await FetchNotionDataAsync();
           return ParseDataToList(jsonData, columnOrder);
       }

       private async Task<string> FetchNotionDataAsync()
       {
           var client = new RestClient($"https://api.notion.com/v1/databases/{_dbKey}/query");
           var request = new RestRequest();
           request.Method = Method.Post;
           request.AddHeader("Authorization", $"Bearer {_apiKey}");
           request.AddHeader("Content-Type", "application/json");
           request.AddHeader("Notion-Version", "2021-05-13");

           var response = await client.ExecuteAsync(request);
           return response.Content;
       }

       private DataTable ParseDataToDataTable(string jsonData)
       {
           var jObject = JObject.Parse(jsonData);
           var dataTable = new DataTable();

           var firstResult = jObject["results"]?.FirstOrDefault() as JObject;
           var properties = firstResult?["properties"] as JObject;

           if (properties == null) return null;

           foreach (var property in properties)
           {
               dataTable.Columns.Add(property.Key.Replace(" ", "_"));
           }

           foreach (var result in jObject["results"])
           {
               var row = dataTable.NewRow();
               var propertyValues = ParseProperties(result["properties"] as JObject);

               foreach (DataColumn column in dataTable.Columns)
               {
                   row[column.ColumnName] = propertyValues.ContainsKey(column.ColumnName.Replace("_", " ")) ? propertyValues[column.ColumnName.Replace("_", " ")] : string.Empty;
               }

               dataTable.Rows.Add(row);
           }

           return dataTable;
       }

       /// <summary>
       /// 컬럼의 순서 및 이름을 지정하여 DataTable로 반환합니다.
       /// </summary>
       /// <param name="jsonData"></param>
       /// <param name="columnOrder"></param>
       /// <returns></returns>
       private DataTable ParseDataToDataTable(string jsonData, List<string> columnOrder)
       {
           var jObject = JObject.Parse(jsonData);
           var dataTable = new DataTable();

           var firstResult = jObject["results"]?.FirstOrDefault() as JObject;
           var properties = firstResult?["properties"] as JObject;

           if (properties == null) return null;

           foreach (var column in columnOrder)
           {
               dataTable.Columns.Add(column);
           }

           foreach (var result in jObject["results"])
           {
               var row = dataTable.NewRow();
               var propertyValues = ParseProperties(result["properties"] as JObject);

               foreach (DataColumn column in dataTable.Columns)
               {
                   row[column.ColumnName] = propertyValues.ContainsKey(column.ColumnName) ? propertyValues[column.ColumnName] : string.Empty;
               }

               dataTable.Rows.Add(row);
           }

           return dataTable;

       }

       private List<Dictionary<string, string>> ParseDataToList(string jsonData)
       {
           var jObject = JObject.Parse(jsonData);
           var resultsList = new List<Dictionary<string, string>>();

           foreach (var result in jObject["results"])
           {
               var propertyValues = ParseProperties(result["properties"] as JObject);
               resultsList.Add(propertyValues);
           }

           return resultsList;
       }

       /// <summary>
       /// 컬럼의 순서 및 이름을 지정하여 Dictionary로 반환합니다.
       /// </summary>
       /// <param name="jsonData"></param>
       /// <param name="columnOrder"></param>
       /// <returns></returns>
       private List<Dictionary<string, string>> ParseDataToList(string jsonData, List<string> columnOrder)
       {
           var jObject = JObject.Parse(jsonData);
           var resultsList = new List<Dictionary<string, string>>();

           foreach (var result in jObject["results"])
           {
               var propertyValues = ParseProperties(result["properties"] as JObject);
               var orderedPropertyValues = new Dictionary<string, string>();

               foreach (var column in columnOrder)
               {
                   orderedPropertyValues[column] = propertyValues.ContainsKey(column) ? propertyValues[column] : string.Empty;
               }

               resultsList.Add(orderedPropertyValues);
           }

           return resultsList;
       }

       private Dictionary<string, string> ParseProperties(JObject properties)
       {
           var parsedProperties = new Dictionary<string, string>();

           foreach (var property in properties)
           {
               var value = property.Value as JObject;
               var propertyType = value?["type"]?.ToString();

               parsedProperties[property.Key] = propertyType switch
               {
                   "title" => string.Join("", value["title"]?.Select(x => x["text"]?["content"]?.ToString()) ?? Enumerable.Empty<string>()),
                   "rich_text" => string.Join("", value["rich_text"]?.Select(x => x["text"]?["content"]?.ToString()) ?? Enumerable.Empty<string>()),
                   "number" => value["number"]?.ToString() ?? "",
                   "select" => value["select"]?["name"]?.ToString() ?? "",
                   "multi_select" => string.Join(", ", value["multi_select"]?.Select(x => x["name"].ToString()) ?? Enumerable.Empty<string>()),
                   "date" => value["date"]?["start"]?.ToString() ?? "",
                   "checkbox" => value["checkbox"]?.ToString() ?? "",
                   "url" => value["url"]?.ToString() ?? "",
                   "email" => value["email"]?.ToString() ?? "",
                   "phone_number" => value["phone_number"]?.ToString() ?? "",
                   "people" => string.Join(", ", value["people"]?.Select(x => x["name"]?.ToString()) ?? Enumerable.Empty<string>()),
                   "files" => string.Join(", ", value["files"]?.Select(x => x["name"]?.ToString()) ?? Enumerable.Empty<string>()),
                   "relation" => string.Join(", ", value["relation"]?.Select(x => x["id"]?.ToString()) ?? Enumerable.Empty<string>()),
                   "formula" => value["formula"]?["string"]?.ToString() ?? "",
                   "created_time" => value["created_time"]?.ToString() ?? "",
                   "created_by" => value["created_by"]?["name"]?.ToString() ?? "",
                   "last_edited_time" => value["last_edited_time"]?.ToString() ?? "",
                   "last_edited_by" => value["last_edited_by"]?["name"]?.ToString() ?? "",
                   "rollup" => value["rollup"]?["type"]?.ToString() == "array"
                       ? string.Join(", ", value["rollup"]?["array"]?.Select(x => x["name"]?.ToString()) ?? Enumerable.Empty<string>())
                       : value["rollup"]?["number"]?.ToString() ?? "",
                   "status" => value["status"]?["name"]?.ToString() ?? "",
                   _ => ""
               };
           }

           return parsedProperties;
       }
   }

Note: 만들고나니 내것이 아니었다.

Leave a comment