Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for stripe pagination #89

Open
nmattia opened this issue Jan 23, 2018 · 0 comments
Open

Add support for stripe pagination #89

nmattia opened this issue Jan 23, 2018 · 0 comments

Comments

@nmattia
Copy link
Contributor

nmattia commented Jan 23, 2018

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant