Unofficial Notion API SDK for iOS & macOS

Overview

NotionSwift

Unofficial Notion SDK for iOS & macOS.

This is still work in progress version, the module interface might change.

API Documentation

This library is a client for the official Notion API. For more details and documentation please check Notion Developer Portal

Installation

CocoaPods

pod 'NotionSwift', '0.4.0'

Swift Package Manager

dependencies: [
    .package(url: "https://github.com/chojnac/NotionSwift.git", .upToNextMajor(from: "0.4.0"))
]

Usage

Currently, this library supports only the "internal integration" authorization mode. For more information about authorization and instruction how to obtain NOTION_TOKEN please check Notion Offical Documentation.

Important: Integrations are granted access to resources (pages and databases) which users have shared with the integration. Resources that are not shared with the integration are not visible by API endpoints.

Creating a Notion client.

let notion = NotionClient(accessKeyProvider: StringAccessKeyProvider(accessKey: "{NOTION_TOKEN}"))

List all databases

The https://api.notion.com/v1/databases is deprecated. To recommended way to list all databases is to use https://api.notion.com/v1/search endpoint. In theory, search allows filtering results by object type. However, currently, the only filter allowed is object which will filter by type of object (either page or database) To narrow search results, use code snippet belove.

// fetch avaiable databases
notion.search(request: .init(filter: .database)) { result in
    let databases = result.map { objects in
        objects.results.compactMap({ object -> Database? in
            if case .database(let db) = object {
                return db
            }
            return nil
        })
    }
    print(databases)
}

Query a database

In this example we will get all pages in the database. To narrow results use params argument.

let databaseId = Database.Identifier("{DATABASE UUIDv4}")

notion.databaseQuery(databaseId: databaseId) {
    print($0)
}

Retrieve a database

let databaseId = Database.Identifier("{DATABASE UUIDv4}")

notion.database(databaseId: databaseId) {
    print($0)
}

Create a database

let parentPageId = Page.Identifier("e67db074-973a-4ddb-b397-66d3c75f9ec9")

let request = DatabaseCreateRequest(
    parent: .pageId(parentPageId),
    icon: .emoji("🤔"),
    cover: .external(url: "https://images.unsplash.com/photo-1606787366850-de6330128bfc"),
    title: [
        .init(string: "Created at: \(Date())")
    ],
    properties: [
        "Field 10": .richText
    ]
)

notion.databaseCreate(request: request) {
    print($0)
}

Update a database

let id = Database.Identifier("{DATABASE UUIDv4}")

// update cover, icon & add a new field
let request = DatabaseUpdateRequest(
    title: nil,
    icon: .emoji("🤔"),
    cover: .external(url: "https://images.unsplash.com/photo-1606787366850-de6330128bfc"),
    properties: [
        "Field 10": .richText
    ]
)

notion.databaseUpdate(databaseId: id, request: request) {
    print($0)
}

Retrieve a page

Retrieve page properties.

let pageId = Block.Identifier("{PAGE UUIDv4}")

notion.page(pageId: pageId) {
    print($0)
}

Page content (text for example) is represented as an array of blocks. The example below loads properties and page content.

let pageId = Block.Identifier("{PAGE UUIDv4}")

notion.page(pageId: pageId) { [notion] in
    print("---- Properties ----- ")
    print($0)
    switch $0 {
    case .success(let page):
        notion.blockChildren(blockId: page.id.toBlockIdentifier) {
            print("---- Children ----- ")
            print($0)
        }
    default:
        break
    }
}

Note: The API returns only the direct children of the page. If there is content nested in the block (nested lists for example) it requires other calls.

Create a page

let parentPageId = Block.Identifier("{PAGE UUIDv4}")

let request = PageCreateRequest(
    parent: .page(parentPageId),
    properties: [
        "title": .init(
            type: .title([
                .init(string: "Lorem ipsum \(Date())")
            ])
        )
    ],
    children: blocks
)

notion.pageCreate(request: request) {
    print($0)
}

Update page properties

let pageId = Block.Identifier("{PAGE UUIDv4}")

// update title property
let request = PageProperiesUpdateRequest(
    properties: [
        .name("title"): .init(
            type: .title([
                .init(string: "Updated at: \(Date())")
            ])
        )
    ]
)

notion.pageUpdateProperties(pageId: pageId, request: request) {
    print($0)
}

Retrieve block children

Note: This endpoint returns only the first level of children, so for example, nested list items won't be returned. In that case, you need to make another request with the block id of the parent block.

let pageId = Block.Identifier("{PAGE UUIDv4}")

notion.blockChildren(blockId: pageId) {
    print($0)
}

Append block children

let pageId = Block.Identifier("{PAGE UUIDv4}")

// append paragraph with styled text to a page.
let blocks: [WriteBlock] = [
    .init(type: .paragraph(.init(text: [
        .init(string: "Lorem ipsum dolor sit amet, "),
        .init(string: "consectetur", annotations: .bold),
        .init(string: " adipiscing elit.")
    ])))
]
notion.blockAppend(blockId: pageId, children: blocks) {
    print($0)
}

Update a block

let blockId = Block.Identifier("{BLOCK UUIDv4}")
let text: [RichText] = [
    .init(string: "Current time: "),
    .init(string: Date().description, annotations: .bold)
]
let block = UpdateBlock(value: .paragraph(text: text))
notion.blockUpdate(blockId: blockId, value: block) {
    print("Updated: ", $0)
}

Block delete

let blockId = Block.Identifier("{BLOCK UUIDv4}")

notion.blockDelete(blockId: block.id) {
    print("Delete: ", $0)
}

Retrieve a user

let id = User.Identifier("{USER UUIDv4}")
notion.user(userId: id) {
    print($0)
}

List all users

notion.usersList() {
    print($0)
}

Search

Search for pages & databases with a title containing text "Lorem"

notion.search(
    request: .init(
        query: "Lorem"
    )
) {
    print($0)
}

Search for all databases and ignore pages.

notion.search(
    request: .init(
        filter: .database
    )
) {
    print($0)
}

Get all pages & databases

notion.search() {
    print($0)
}

Logging and debugging

NotionSwift provide an internal rudimental logging system to track HTTP traffic. To enable it you need to set a build-in or custom logger handler and decide about log level (.info by default). With .track log level you can see all content of a request. This is useful to track mapping issues between library data models and API.

Example logging configuration:

// This code should be in the ApplicationDelegate

NotionSwift.Environment.logHandler = NotionSwift.PrintLogHandler() // uses print command
NotionSwift.Environment.logLevel = .trace // show me everything

License

NotionSwift is available under the MIT license. See the LICENSE file for more info.

Comments
  • API request fails when database contains a Double value not Int

    API request fails when database contains a Double value not Int

    Screenshot 2022-05-29 at 12 21 47 Screenshot 2022-05-29 at 12 21 57

    When trying to query a database that contains a double value (in the example given: 1,000.50) as opposed to a rounded Integer value (1000.00), the request fails and an "Error 3" is returned.

    This happens on Formula property types, number property types and rollup types.

    opened by baxi87 7
  • Create page decoding fails for null link property

    Create page decoding fails for null link property

    I'm using pageCreate to create a page inside a database with some properties. Create request succeed, but the response parse fails due to a null link property.

    This is the error message that I get:

    [ERROR] decoding: valueNotFound(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "properties", intValue: nil), _JSONKey(stringValue: "GCal Link", intValue: nil), CodingKeys(stringValue: "url", intValue: nil)], debugDescription: "Expected String value but found null instead.", underlyingError: nil))
    

    On the Notion database, GCal link is a URL property, that is usually empty:

    Screenshot 2022-08-15 at 10 53 01

    I'm able to reproduce the issue every time, let me know if you need other info!

    wip 
    opened by andreabusi 4
  • Adding new row to multi-column database in notion

    Adding new row to multi-column database in notion

    Is there currently a way with this package to add a new single row to a multi-column database in Notion and map the new values to named columns in the database? Sort of confused on the documentation around this and unsure if it's possible. Thanks for any help, and thanks for creating this great project.

    opened by corybohon 4
  • Handled null number value in rollup property

    Handled null number value in rollup property

    I got this deserialisation error:

    valueNotFound(__C.NSDecimal, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "properties", intValue: nil), _JSONKey(stringValue: "Progress", intValue: nil), CodingKeys(stringValue: "rollup", intValue: nil), CodingKeys(stringValue: "number", intValue: nil)], debugDescription: "Expected NSDecimal value but found null instead.", underlyingError: nil))

    when the page retrieved from Notion had this property:

    "Progress":{
       "id":"fmwt",
       "type":"rollup",
       "rollup":{
          "type":"number",
          "number":null,
          "function":"percent_checked"
       }
    }
    

    so I've made the number nullable and added a unit test for Page deserialisation. Wasn't sure if the test was needed, let me know if you think it's too much or whether the test name should be more general.

    opened by miszu 2
  • OAuth Support

    OAuth Support

    Thanks for what you're doing with this project.

    In the README it is stated:

    Currently, this library supports only the "internal integration" authorization mode.

    I'm not too familiar with OAuth, but from the Notion docs it seemed as though once the OAuth flow has succeeded you are simply given a token which can be used in essentially the same way as a personal token. Are there differences in how you interact with the API when using OAuth (such that changes would be needed in this package in order to support it)?

    opened by undecoded-coder 2
  • Unable to update database due to missing icons

    Unable to update database due to missing icons

    I want to update the properties on my database, but am unable to because of Notion error 1.

    let request = DatabaseUpdateRequest(title: database.title, icon: database.icon, cover: database.cover, properties: updatedProperties)

    body validation failed. Fix one: body.icon.emoji should be defined, instead was undefined. body.icon.external should be defined, instead was undefined.

    I'm not sure why the icons would matter when updating properties. But anyway, I got the error with a database that had only an icon and no cover. And also on a database with both an icon and cover image.

    opened by JaydenIrwin 2
  • Unable to set a page relation during Page Create Request

    Unable to set a page relation during Page Create Request

    Hi team!

    Am creating a new page in a database, that includes a relation field ("User"). But am receiving this validation error message back from the API:

    failure(NotionSwift.NotionClientError.apiError(status: 400, code: "validation_error", message: "body failed validation: body.properties.User.relation[0] should be an object, instead was \"a8073fb6-1fad-4aa8-93fc-31474eb77529\"."))

    My original page request properties are set out as follows:

    properties: [
                    "Name": .init(
                        type: .title([
                            .init(string: "A new session was started")
                        ])
                    ),
                    "identifier": .init(
                        type: .richText([
                            .init(string: "\(self.user.id?.uuidString ?? "Unknown user")")
                        ])
                    ),
                    "User": .init(type: .relation([.init("a8073fb61fad4aa893fc31474eb77529")])),
                    "Tags": .init(
                        type: .multiSelect([
                            .init(id: nil, name: "Hello", color: nil)
                        ])
                    )
                ],
    
    

    The original request output for the relation field shows as follows: "User": NotionSwift.WritePageProperty(type: NotionSwift.PagePropertyType.relation([ID:a8073fb6-1fad-4aa8-93fc-31474eb77529]))

    I've spent hours trying to resolve it, if the error is on my side, or you need more info to investigate. Do let me know.

    wip 
    opened by baxi87 2
  • Rename Environment

    Rename Environment

    Could you rename Environment? It conflicts with SwiftUI and gives the error "'Environment' is ambiguous for type lookup in this context" when I try to use @Environment variables.

    opened by JaydenIrwin 2
  • Support URL property in Page responses

    Support URL property in Page responses

    Notion vends a page's URL via the url property in Page object responses. The Page type in NotionSwift does not seem to support this property however. As far as I can tell implementing this would mostly just be adding a url property to the Page type.

    Reference: Notion documentation for the Page object.

    You can verify it is included in responses with NotionSwift trace-level logging enabled.

    opened by undecoded-coder 1
  • Included Name property in DatabaseProperty type

    Included Name property in DatabaseProperty type

    Hey, thanks a lot for creating and maintaining this package 💫

    I've noticed that DatabaseProperty model does not contain the name field, even though it is returned from the API (https://developers.notion.com/changelog/database-property-objects-now-include-property-name). I've tested it quickly and it seems to work fine, name is deserialised and looks exactly like in Notion.

    opened by miszu 1
  • Allow rollup number value to be nil

    Allow rollup number value to be nil

    Addressing issue #26

    In theory number in value in rollup always should have a value, but based on bug reports, there are situations where API returns a null value.

    opened by chojnac 1
  • Add

    Add "Retrieve page property item" endpoint

    Add the new endpoint described in this post https://developers.notion.com/changelog/retrieve-page-property-values

    It's a bit strange design because we will get an object for some properties, but for others (title, rich_text, relation, rollup, and people), we will get a result list with pagination.

    opened by chojnac 0
Releases(0.7.3)
  • 0.7.3(Aug 16, 2022)

  • 0.7.2(May 30, 2022)

  • 0.7.0(May 3, 2022)

    • [BREAKING] Change name for the Environment struct to NotionSwiftEnvironment to fix name conflicts in SwiftUI
    • Improve constructor for DatabasePropertyType.SelectOption for easier when adding new select/multiselect options.
    Source code(tar.gz)
    Source code(zip)
  • 0.6.0(Apr 17, 2022)

    • Add support for creating columns from code
    • Refactor and improve ergonomics for creating blocks from code.
    • Update code to support API in version 2022-02-22
    • Rename text property to richText and deprecate old property name usages.
    • [Breaking] Changes in filter property names.
    • Add support for color property in some blocks
    • Add support for lastEditedBy & createdBy in pages, database & blocks
    • Add support for table & table_row blocks with nice interface for creating it programaticly
    • Bump minimal supported iOS version to iOS 11 and macOS to 10.13
    Source code(tar.gz)
    Source code(zip)
  • 0.5.1(Dec 3, 2021)

  • 0.5.0(Nov 21, 2021)

  • 0.4.0(Oct 31, 2021)

    • Add new block types: callout, quote, equation, embed, bookmark, media (video, audio, image, file, pdf), column, column list, breadcrumbs
    • Retrieve your token's bot user with GET /v1/users/me
    • Database objects now contains url property
    • Add static builders for the new block types
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Sep 19, 2021)

  • 0.2.0(Jun 7, 2021)

    • Add missing database endpoint query parameters
    • Add missing public constructors for model objects
    • Add support for the Combine framework (here comes the SwiftUI)
    Source code(tar.gz)
    Source code(zip)
Owner
Wojciech Chojnacki
iOS developer
Wojciech Chojnacki
Alter SDK is a cross-platform SDK consisting of a real-time 3D avatar system, facial motion capture, and an Avatar Designer component built from scratch for web3 interoperability and the open metaverse.

Alter SDK is a cross-platform SDK consisting of a real-time 3D avatar system, facial motion capture, and an Avatar Designer component built from scratch for web3 interoperability and the open metaverse.

Alter 45 Nov 29, 2022
150,000+ stickers API & SDK for iOS Apps.

English | 한국어 Stipop UI SDK for iOS Stipop SDK provides over 150,000 .png and .gif stickers that can be easily integrated into mobile app chats, comme

Stipop, Inc. 19 Dec 20, 2022
iOS SDK for the Box Content API

Box iOS SDK Getting Started Docs: https://developer.box.com/guides/mobile/ios/quick-start/ NOTE: The Box iOS SDK in Objective-C (prior to v3.0.0) has

Box 112 Dec 19, 2022
iOS SDK for access the OpenCage Geocoding API

OpenCageSDK Requirements OpenCageSDK works on iOS 9+ and requires ARC to build. It depends on the following Apple frameworks, which should already be

OpenCage GmbH 1 Jun 30, 2020
RadioTimeKit - The Swift SDK for TuneIn RadioTimeKit is a Swift package to use the TuneIn API.

RadioTimeKit - The Swift SDK for TuneIn RadioTimeKit is a Swift package to use the TuneIn API. The goal for development was to have a Swift SDK to get

Frank Gregor 2 Jun 20, 2022
Swift SDK for Blockfrost.io API

Swift5 API client for Blockfrost Swift 5 SDK for Blockfrost.io API. Installation • Usage • API Endpoints Installation Swift package manager dependenci

blockfrost.io 10 Dec 24, 2022
MpesaSDK - Swift SDK for the M-Pesa API (Mozambique)

M-Pesa SDK Swift package for M-Pesa API (Mozambique) Ready Methods/APIs C2B B2B

Algy Ali 16 Jul 29, 2022
MbientLab 2 Feb 5, 2022
Business-API - Business App an Application that show list business using the Yelp API

business-API Business App an Application that show list business using the Yelp

Edwin Niwarlangga 0 Jan 21, 2022
Native iOS implementation of RadarCOVID tracing client using DP3T iOS SDK

RadarCOVID iOS App Introduction Native iOS implementation of RadarCOVID tracing client using DP3T iOS SDK Prerequisites These are the tools used to bu

Radar COVID 146 Nov 24, 2022
Open-source API Client for iOS, iPadOS, macOS. Built with SwiftUI

Yogu Open-source API Client for iOS, iPadOS, macOS. Built with SwiftUI ?? Yogu is currently in development, and not actually usable yet. Please DO NOT

Beomjun Gil 5 Oct 29, 2022
TelegramStickersImport — Telegram stickers importing SDK for iOS

TelegramStickersImport — Telegram stickers importing SDK for iOS TelegramStickersImport helps your users import third-party programaticaly created sti

null 35 Oct 26, 2022
Muxer used on top of Feed iOS SDK for airplay

FeedAirplayMuxer Muxer used on top of Feed iOS SDK for airplay purposes. Demo Project --> https://github.com/feedfm/AirplayDemo Feed Airplay Muxer is

Feed Media 0 May 6, 2022
Basispay IOS SDK Version 2

BasisPay-IOS-KIT BasisPay IOS Payment Gateway kit for developers INTRODUCTION This document describes the steps for integrating Basispay online paymen

null 0 Oct 21, 2021
Release repo for Gini Bank SDK for iOS

Gini Bank SDK for iOS The Gini Bank SDK provides components for capturing, reviewing and analyzing photos of invoices and remittance slips. By integra

Gini GmbH 1 Dec 6, 2022
Da Xue Zhang Platform Lvb iOS SDK

Cloud_Lvb_SDK iOS API Reference Dxz Meeting iOS SDK是为 iOS 平台用户音视频服务的开源 SDK。通过大学长开放平台自研RTC,RTM系统,为客户提供质量可靠的音视频服务。 类 类名 描述 CLS_PlatformManager SDK的音视频主要

null 8 Jan 10, 2022
PayPal iOS SDK

PayPal iOS SDK Welcome to PayPal's iOS SDK. This library will help you accept card, PayPal, Venmo, and alternative payment methods in your iOS app. Su

PayPal 25 Dec 14, 2022
Spotify SDK for iOS

Spotify iOS SDK Overview The Spotify iOS framework allows your application to interact with the Spotify app running in the background on a user's devi

Spotify 522 Jan 6, 2023
Headless iOS/Mac SDK for saving stuff to Pocket.

This SDK is deprecated Howdy all! ?? Thanks for checking out this repo. Your ?? mean a lot to us. ?? Unfortunately, this project is deprecated, and th

Pocket 230 Mar 18, 2022