notion-client-effectful: Effectful effects for notion-client

[ library, mit, web ] [ Propose Tags ] [ Report a vulnerability ]

Effectful effect and default interpreter for notion-client. Exposes every operation on Notion.V1.Methods as a smart constructor of the Notion.V1.Effectful.Notion effect and provides a runNotion interpreter that dispatches through a concrete Methods value. API-level Notion.V1.Error.NotionError responses are surfaced via the Error NotionError effect; other Servant.Client.ClientError values and OAuth lifecycle or persistence failures remain IO exceptions. Accepts fixed-token or refreshing Methods without changing effect operations. See README.md for the full import pattern and a worked example.


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.2.0.0, 0.3.0.0, 0.4.0.0
Change log CHANGELOG.md
Dependencies aeson (>=2.2 && <2.3), base (>=4.18 && <5), effectful-core (>=2.5 && <3), notion-client (>=0.10 && <0.11), text (>=2.0 && <2.2) [details]
Tested with ghc ==9.12.4
License MIT
Author Nadeem Bitar
Maintainer nadeem@gmail.com
Uploaded by shinzui at 2026-10-19T23:09:54Z
Category Web
Home page https://github.com/shinzui/notion-client/tree/master/notion-client-effectful
Bug tracker https://github.com/shinzui/notion-client/issues
Source repo head: git clone https://github.com/shinzui/notion-client.git(notion-client-effectful)
Distributions
Downloads 15 total (12 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for notion-client-effectful-0.4.0.0

[back to package description]

notion-client-effectful

An effectful surface for notion-client.

This package wraps the Notion.V1.Methods record as a dynamic effect — so code written against effectful does not have to thread the Methods value through every call site and does not have to drop into IO at each API boundary.

Purpose

notion-client exposes a single Methods record whose fields are IO-typed API calls. That is ergonomic for a plain-IO program but awkward for an effectful-based caller: every call requires liftIO and escapes the ambient Error / Reader / Log stack.

notion-client-effectful gives that caller an equivalent set of operations surfaced as an Effect so the stack is preserved.

Import pattern

Every smart constructor shares its name with the matching Notion.V1.Methods record selector. That is on purpose — it keeps migration from IO mechanical — but it means a file that imports both modules unqualified will see name clashes. Import one of the two qualified:

import Notion.V1                    (Methods, getClientEnv, makeMethods)
import Notion.V1.Effectful qualified as NE

Then NE.retrievePage, NE.search, NE.runNotion, and so on.

The umbrella module exposes the common operations. For the complete surface, including filtered page requests, background operations, meeting notes and comment retrieval/update/deletion, import the effect and interpreter directly:

import Notion.V1.Effectful.Effect qualified as NE
import Notion.V1.Effectful.Interpreter (runNotion)

Use NE.createPageFiltered, NE.createPageAsync, NE.retrieveAsyncTask, and the other effect operations with the unqualified runNotion interpreter.

Error handling

runNotion catches Notion.V1.Error.NotionError thrown by the underlying Methods and re-raises it via the Error NotionError effect, so callers can branch on API error shapes (object_not_found, validation failures, etc.) without reaching for IO-level exception handling.

Other Servant.Client.ClientError values — network failures, decoding errors — are not caught and remain IO exceptions. This preserves the contract of the underlying notion-client library and lets callers layer their own Error ClientError interpretation on top later. The same applies to UnknownHTTPResponseError, RequestTimeoutError and InvalidPathParameterError from Notion.V1.Error. Retries of rate-limited requests and reactive OAuth renewal happen inside Methods, before an error reaches runNotion.

OAuth installations

Build Methods with core makeMethodsWithTokenSource and pass it to runNotion; existing effect operations need no changes. See the core OAuth walkthrough for browser login and token-store setup.

OAuthError, ReauthorizationRequired, TokenPersistenceError and RefreshOutcomeUnknown propagate as IO exceptions. Handle them at the application boundary outside runEff; Error NotionError catches only final Notion API errors. For a persistence failure, call retryTokenPersistence on the same manager to save its retained pair without another refresh. Reauthorization or an uncertain remote outcome requires a new login and manager. Use one manager per installation; multiple processes must coordinate the entire load/refresh/save sequence.

Minimum viable usage

Use GHC2024 with OverloadedStrings for this example.

module Demo where

import Data.Text (Text)
import Data.Text qualified as Text
import Effectful (Eff, runEff, (:>))
import Effectful.Error.Static (Error, runErrorNoCallStack)
import Notion.V1                    (getClientEnv, makeMethods)
import Notion.V1.Common             (UUID (..))
import Notion.V1.Effectful qualified as NE
import Notion.V1.Error              (NotionError)
import System.Environment qualified as Env

demo ::
  (NE.Notion :> es, Error NotionError :> es) =>
  UUID ->
  Eff es Text
demo pid = do
  page <- NE.retrievePage pid
  pure (Text.pack (show page))

main :: IO ()
main = do
  token <- Text.pack <$> Env.getEnv "NOTION_TOKEN"
  env <- getClientEnv "https://api.notion.com/v1"
  let methods = makeMethods env token
  result <-
    runEff
      . runErrorNoCallStack @NotionError
      . NE.runNotion methods
      $ demo (UUID "00000000-0000-0000-0000-000000000000")
  print result

What you get

One smart constructor per field of Notion.V1.Methods. The argument types and order match the underlying field, so an existing call like

page <- retrievePage methods pid

becomes

page <- NE.retrievePage pid

with no other change to the call site.

Versioning

Use compatible versions of both packages:

notion-client-effectful Required notion-client
0.4.x >=0.10 && <0.11
0.3.x >=0.9 && <0.10
0.2.x >=0.8 && <0.9

The prepared release is notion-client-effectful-0.4.0.0 with notion-client-0.10.0.0. The companion's core bound moves with each breaking core release, even when Methods fields are unchanged. See the changelog for migration details and the repository's release preparation for validation.