It would be nice if the library supported pagination natively, so that the user doesn't have to do it themself. The wreq library, for instance, has some basic support for this.
I'm not sure what exactly this should look like, and if the library wants to provide such higher-level helpers at all. Just in case, here's a naive conduit implementation:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-|
Copyright: 2017 (C) AlphaSheets, Inc
Description: Conduit support for 'Web.Stripe'
-}
module Web.Stripe.Conduit where
import Control.Monad
import Control.Monad.Catch
import Control.Monad.IO.Class
import Data.Aeson
import Data.Conduit
import Safe (lastMay)
import Web.Stripe (stripe, (-&-))
import qualified Data.Conduit.List as CL
import qualified Web.Stripe as Stripe
import qualified Web.Stripe.Customer as Stripe
-- | Create a conduit request to `Stripe`'s API
stripeConduit
:: (MonadIO m, FromJSON (Stripe.StripeReturn a)
, Stripe.StripeReturn a ~ Stripe.StripeList b
, Stripe.StripeHasParam a (Stripe.StartingAfter id)
, MonadThrow m)
=> Stripe.StripeConfig
-> Stripe.StripeRequest a
-> (b -> id)
-- ^ A mapping between the type and its ID field used in pagination
-- TODO: the user should not have to set this themself
-> Source m b
stripeConduit config request toId = do
res <- liftIO $ stripe config request
case res of
Left e -> throwM e
Right slist -> do
-- Yield all objs already present
let objs = Stripe.list slist
CL.sourceList objs
-- Paginate
when (Stripe.hasMore slist) $ do
lastId <- case toId <$> lastMay objs of
Just lastId -> pure lastId
Nothing -> throwM Stripe.StripeError
{ Stripe.errorType = Stripe.APIError
, Stripe.errorMsg = "Stripe returned an empty list"
, Stripe.errorCode = Nothing
, Stripe.errorParam = Nothing
, Stripe.errorHTTP = Nothing
}
stripeConduit
config
(request -&- Stripe.StartingAfter lastId)
toId
It would be nice if the library supported pagination natively, so that the user doesn't have to do it themself. The
wreq
library, for instance, has some basic support for this.I'm not sure what exactly this should look like, and if the library wants to provide such higher-level helpers at all. Just in case, here's a naive conduit implementation: