notion-api-client/src/hff_notion_api_client.nim

186 lines
6.4 KiB
Nim

import std/httpclient, std/json, std/logging, std/sequtils, std/tables, std/strutils
import buffoonery/jsonutils
import hff_notion_api_client/config
import hff_notion_api_client/models
import hff_notion_api_client/sequtils_ext
import hff_notion_api_client/utils
type
NotionClientConfig* = object
apiBaseUrl*: string
apiVersion*: string
configDbId*: string
integrationToken*: string
NotionClient* = ref object
http: HttpClient
apiBaseUrl: string
config*: HffNotionConfig
proc loadNotionConfig(http: HttpClient, cfg: NotionClientConfig): HffNotionConfig =
let url = cfg.apiBaseUrl & "/databases/" & cfg.configDbId & "/query"
let body = $(%*{ "page_size": NOTION_MAX_PAGE_SIZE })
debug "loadNotionConfig\n\tPOST " & url & "\n\t" & $body
let resp = http.postContent(url, body)
let resultsJson = parseJson(resp)["results"]
result = parseHffNotionConfig(resultsJson)
proc initNotionClient*(cfg: NotionClientConfig): NotionClient =
result = NotionClient(
apiBaseUrl: cfg.apiBaseUrl,
http: newHttpClient(headers = newHttpHeaders([
("Content-Type", "application/json"),
("Authorization", "Bearer " & cfg.integrationToken),
("Notion-Version", cfg.apiVersion)
], true)))
result.config = result.http.loadNotionConfig(cfg)
proc `%`*(c: NotionClientConfig): JsonNode =
%*{
"apiBaseUrl": c.apiBaseUrl,
"apiVersion": c.apiVersion,
"configDbId": c.configDbId,
"integrationToken": c.integrationToken
}
proc parseNotionClientConfig*(n: JsonNode): NotionClientConfig =
NotionClientConfig(
apiBaseUrl: n.getOrFail("apiBaseUrl").getStr,
apiVersion: n.getOrFail("apiVersion").getStr,
configDbId: n.getOrFail("configDbId").getStr,
integrationToken: n.getOrFail("integrationToken").getStr)
proc fetchAllPages*(
http: HttpClient,
url: string,
bodyTemplate = %*{ "page_size": NOTION_MAX_PAGE_SIZE}): seq[JsonNode] =
result = @[]
var nextCursor: string = ""
while true:
let body = parseJson($bodyTemplate)
if not nextCursor.isEmptyOrWhitespace: body["start_cursor"] = %nextCursor
debug "Fetching pages from database:\n\tPOST " & url & "\n\t" & $body
let jsonResp = parseJson(http.postContent(url, $body))
result = result & jsonResp["results"].getElems
if jsonResp.hasKey("next_cursor") and jsonResp["next_cursor"].kind != JNull:
nextCursor = jsonResp["next_cursor"].getStr
if nextCursor.isEmptyOrWhitespace: break
template fetchDatabaseObject*(notion: NotionClient, dbId: string): untyped =
let resp = notion.http.get(notion.apiBaseUrl & "/databases/" & dbId)
if not resp.status.startsWith("2"):
debug resp.body
raise newException(HttpRequestError, "API Request failed: " & resp.body)
parseJson(resp.body)
template fetchPage*(notion: NotionClient, pageId: string): untyped =
let resp = notion.http.get(notion.apiBaseUrl & "/pages/" & pageId)
if not resp.status.startsWith("2"):
debug resp.body
raise newException(HttpRequestError, "API Request failed: " & resp.body)
parseJson(resp.body)
template createDbPage*(notion: NotionClient, parentDbId: string, r: typed): untyped =
let page = r.toPage
page["parent"] = %*{ "database_id": parentDbId }
let resp = notion.http.post(notion.apiBaseUrl & "/pages", $page)
if not resp.status.startsWith("2"):
debug resp.body
raise newException(HttpRequestError, "API Request failed: " & resp.body)
parseJson(resp.body)
template updatePage*(notion: NotionClient, r: typed): JsonNode =
let page = r.toPage
let resp = notion.http.patch(notion.apiBaseUrl & "/pages/" & r.id, $page)
if not resp.status.startsWith("2"): debug resp.body
parseJson(resp.body)
template delete*(notion: NotionClient, r: typed): string =
let resp = notion.http.delete(notion.apiBaseUrl & "/blocks/" & r.id)
if not resp.status.startsWith("2"): debug resp.body
parseJson(resp.body)["id"].getStr
proc fetchSyncRecords*(notion: NotionClient): seq[SyncRecord] =
let respRecords = notion.http.fetchAllPages(
notion.apiBaseUrl & "/databases/" & notion.config.syncRecordsDbId & "/query")
return respRecords.mapIt(syncRecordFromPage(it))
proc create*(notion: NotionClient, r: SyncRecord): SyncRecord =
return syncRecordFromPage(createDbPage(notion, notion.config.syncRecordsDbId, r))
proc update*(notion: NotionClient, r: SyncRecord): SyncRecord =
return syncRecordFromPage(updatePage(notion, r))
proc fetchAddress*(notion: NotionClient, addressId: string): Address =
return addressFromPage(notion.fetchPage(addressId))
proc fetchAddresses*(notion: NotionClient): seq[Address] =
let respRecords = notion.http.fetchAllPages(
notion.apiBaseUrl & "/databases/" & notion.config.addressesDbId & "/query")
return resprecords.mapIt(addressFromPage(it))
proc create*(notion: NotionClient, a: Address): Address =
return addressFromPage(notion.createDbPage(notion.config.addressesDbId , a))
proc update*(notion: NotionClient, r: Address): Address =
return addressFromPage(updatePage(notion, r))
proc fetchFamily*(notion: NotionClient, familyId: string): Family =
return familyFromPage(notion.fetchPage(familyId))
proc fetchFamilies*(notion: NotionClient): seq[Family] =
let respRecords = notion.http.fetchAllPages(
notion.apiBaseUrl & "/databases/" & notion.config.familiesDbId & "/query")
return respRecords.mapIt(familyFromPage(it))
proc create*(notion: NotionClient, f: Family): Family =
return familyFromPage(notion.createDbPage(notion.config.familiesDbId , f))
proc update*(notion: NotionClient, r: Family): Family =
return familyFromPage(updatePage(notion, r))
proc fetchPerson*(notion: NotionClient, personId: string): Person =
return personFromPage(notion.fetchPage(personId))
proc fetchPeople*(notion: NotionClient): seq[Person] =
let respRecords = notion.http.fetchAllPages(
notion.apiBaseUrl & "/databases/" & notion.config.peopleDbId & "/query")
return respRecords.mapIt(personFromPage(it))
proc create*(notion: NotionClient, p: Person): Person =
return personFromPage(notion.createDbPage(notion.config.peopleDbId, p))
proc update*(notion: NotionClient, r: Person): Person =
return personFromPage(updatePage(notion, r))
proc persist*[T](notion: NotionClient, r: T): T =
if r.id.isEmptyOrWhitespace: notion.create(r)
else: notion.update(r)
proc fetchMembershipDataSet*(notion: NotionClient): MembershipDataSet =
result = MembershipDataSet(
addresses: mapById(notion.fetchAddresses()),
families: mapById(notion.fetchFamilies()),
people: mapById(notion.fetchPeople()))