stripe-servant (empty) → 0.1.0.0
raw patch · 7 files changed
+427/−0 lines, 7 filesdep +aesondep +basedep +casingsetup-changed
Dependencies added: aeson, base, casing, http-api-data, servant, text, time, unordered-containers, vector
Files
- LICENSE +30/−0
- README.md +5/−0
- Setup.hs +2/−0
- src/Stripe/Api.hs +47/−0
- src/Stripe/Resources.hs +278/−0
- src/Stripe/Util/Aeson.hs +16/−0
- stripe-servant.cabal +49/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Alexander Thiemann <mail@thiemann.at> (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Author name here nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,5 @@+# stripe-servant++Unofficial and incomplete description of the Stripe API using servant types. Contributions are welcome!++For usage, see the `stripe-hs` package.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Stripe/Api.hs view
@@ -0,0 +1,47 @@+-- | The API++module Stripe.Api where++import Stripe.Resources++import Servant.API+import qualified Data.Text as T++type StripeAuth = BasicAuth "Stripe API" ()++type StripeApi+ = "v1" :> StripeApiInternal++type StripeApiInternal+ = "customers" :> CustomerApi+ :<|> "products" :> ProductApi+ :<|> "prices" :> PriceApi+ :<|> "checkout" :> "sessions" :> CheckoutApi+ :<|> "billing_portal" :> "sessions" :> CustomerPortalApi+ :<|> "events" :> EventApi++type CustomerApi+ = StripeAuth :> ReqBody '[FormUrlEncoded] CustomerCreate :> Post '[JSON] Customer+ :<|> StripeAuth :> Capture ":customer_id" CustomerId :> Get '[JSON] Customer+ :<|> StripeAuth :> Capture ":customer_id" CustomerId :> ReqBody '[FormUrlEncoded] CustomerUpdate :> Post '[JSON] Customer+ :<|> StripeAuth :> QueryParam "starting_after" CustomerId :> Get '[JSON] (StripeList Customer)++type EventApi+ = StripeAuth :> Capture ":event_id" EventId :> Get '[JSON] Event+ :<|> StripeAuth :> QueryParam "starting_after" EventId :> Get '[JSON] (StripeList Event)++type ProductApi+ = StripeAuth :> ReqBody '[FormUrlEncoded] ProductCreate :> Post '[JSON] Product+ :<|> StripeAuth :> Capture ":product_id" ProductId :> Get '[JSON] Product++type PriceApi+ = StripeAuth :> ReqBody '[FormUrlEncoded] PriceCreate :> Post '[JSON] Price+ :<|> StripeAuth :> Capture ":product_id" PriceId :> Get '[JSON] Price+ :<|> StripeAuth :> QueryParam "lookup_keys[]" T.Text :> Get '[JSON] (StripeList Price)++type CheckoutApi+ = StripeAuth :> ReqBody '[FormUrlEncoded] CheckoutSessionCreate :> Post '[JSON] CheckoutSession+ :<|> StripeAuth :> Capture ":session_id" CheckoutSessionId :> Get '[JSON] CheckoutSession++type CustomerPortalApi+ = StripeAuth :> ReqBody '[FormUrlEncoded] CustomerPortalCreate :> Post '[JSON] CustomerPortal
+ src/Stripe/Resources.hs view
@@ -0,0 +1,278 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+module Stripe.Resources+ ( -- * Core Types+ TimeStamp(..), StripeList(..)+ -- * Customers+ , CustomerId(..), Customer(..), CustomerCreate(..), CustomerUpdate(..)+ -- * Product catalog+ , ProductId(..), PriceId(..)+ , Product(..), ProductCreate(..)+ , Price(..), PriceRecurring(..), PriceCreate(..), PriceCreateRecurring(..)+ -- * Subscriptions+ , SubscriptionId(..)+ -- * Customer Portal+ , CustomerPortalId(..), CustomerPortal(..), CustomerPortalCreate(..)+ -- * Checkout+ , CheckoutSessionId(..), CheckoutSession(..), CheckoutSessionCreate(..), CheckoutSessionCreateLineItem(..)+ -- * Events+ , EventId(..), Event(..), EventData(..)+ )+where++import Stripe.Util.Aeson++import Data.Maybe+import Data.Time+import Data.Time.Clock.POSIX+import GHC.Generics+import Servant.API+import Text.Casing (quietSnake)+import Web.FormUrlEncoded+import qualified Data.Aeson as A+import qualified Data.HashMap.Strict as HM+import qualified Data.Text as T+import qualified Data.Vector as V++formOptions :: Int -> FormOptions+formOptions x =+ FormOptions+ { fieldLabelModifier = quietSnake . drop x }++-- | A 'UTCTime' wrapper that has unix timestamp JSON representation+newtype TimeStamp+ = TimeStamp { unTimeStamp :: UTCTime }+ deriving (Show, Eq)++instance A.ToJSON TimeStamp where+ toJSON = A.Number . fromRational . toRational . utcTimeToPOSIXSeconds . unTimeStamp++instance A.FromJSON TimeStamp where+ parseJSON =+ A.withScientific "unix timestamp" $ \sci ->+ pure $ TimeStamp $ posixSecondsToUTCTime (fromRational $ toRational sci)++-- | A 'V.Vector' wrapper with an indication is there are more items available through pagination.+data StripeList a+ = StripeList+ { slHasMore :: Bool+ , slData :: V.Vector a+ } deriving (Show, Eq)++newtype CustomerId+ = CustomerId { unCustomerId :: T.Text }+ deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data Customer+ = Customer+ { cId :: CustomerId+ , cLivemode :: Bool+ , cCreated :: TimeStamp+ , cName :: Maybe T.Text+ , cEmail :: Maybe T.Text+ } deriving (Show, Eq)++data CustomerCreate+ = CustomerCreate+ { ccName :: Maybe T.Text+ , ccEmail :: Maybe T.Text+ } deriving (Show, Eq, Generic)++data CustomerUpdate+ = CustomerUpdate+ { cuName :: Maybe T.Text+ , cuEmail :: Maybe T.Text+ } deriving (Show, Eq, Generic)++newtype EventId+ = EventId { unEventId :: T.Text }+ deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data Event+ = Event+ { eId :: EventId+ , eCreated :: TimeStamp+ , eLivemode :: Bool+ , eType :: T.Text+ , eApiVersion :: T.Text+ , eData :: EventData+ } deriving (Show, Eq)++data EventData+ = EventData+ { edObject :: A.Value+ } deriving (Show, Eq)++newtype PriceId+ = PriceId { unPriceId :: T.Text }+ deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data Price+ = Price+ { pId :: PriceId+ , pActive :: Bool+ , pCurrency :: T.Text+ , pNickname :: Maybe T.Text+ , pType :: T.Text -- TODO: make enum+ , pRecurring :: Maybe PriceRecurring+ , pUnitAmount :: Maybe Int+ , pProduct :: ProductId+ , pLookupKey :: Maybe T.Text+ } deriving (Show, Eq)++data PriceRecurring+ = PriceRecurring+ { prInterval :: T.Text -- TODO: make enum+ , prIntervalCount :: Int+ } deriving (Show, Eq)++data PriceCreate+ = PriceCreate+ { pcCurrency :: T.Text+ , pcUnitAmount :: Maybe Int+ , pcProduct :: ProductId+ , pcLookupKey :: Maybe T.Text+ , pcTransferLookupKey :: Bool+ , pcRecurring :: Maybe PriceCreateRecurring+ } deriving (Show, Eq, Generic)++data PriceCreateRecurring+ = PriceCreateRecurring+ { prcInterval :: T.Text -- TODO: make enum+ , prcIntervalCount :: Maybe Int+ } deriving (Show, Eq)++newtype ProductId+ = ProductId { unProductId :: T.Text }+ deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data Product+ = Product+ { prId :: ProductId+ , prActive :: Bool+ , prName :: T.Text+ , prDescription :: Maybe T.Text+ } deriving (Show, Eq)++data ProductCreate+ = ProductCreate+ { prcName :: T.Text+ , prcDescription :: Maybe T.Text+ } deriving (Show, Eq, Generic)++newtype SubscriptionId+ = SubscriptionId { unSubscriptionId :: T.Text }+ deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++newtype CheckoutSessionId+ = CheckoutSessionId { unCheckoutSessionId :: T.Text }+ deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data CheckoutSession+ = CheckoutSession+ { csId :: CheckoutSessionId+ , csLivemode :: Bool+ , csClientReferenceId :: Maybe T.Text+ , csCancelUrl :: T.Text+ , csSuccessUrl :: T.Text+ , csPaymentMethodTypes :: V.Vector T.Text -- TODO: make enum+ , csSubscription :: Maybe SubscriptionId+ } deriving (Show, Eq)++data CheckoutSessionCreate+ = CheckoutSessionCreate+ { cscCancelUrl :: T.Text+ , cscMode :: T.Text -- TODO: make enum+ , cscPaymentMethodTypes :: [T.Text] -- TODO: make enum+ , cscSuccessUrl :: T.Text+ , cscClientReferenceId :: Maybe T.Text+ , cscCustomer :: Maybe CustomerId+ , cscLineItems :: [CheckoutSessionCreateLineItem]+ } deriving (Show, Eq, Generic)++data CheckoutSessionCreateLineItem+ = CheckoutSessionCreateLineItem+ { cscliPrice :: PriceId+ , cscliQuantity :: Integer+ } deriving (Show, Eq, Generic)++newtype CustomerPortalId+ = CustomerPortalId { unCustomerPortalId :: T.Text }+ deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data CustomerPortal+ = CustomerPortal+ { cpId :: CustomerPortalId+ , cpLivemode :: Bool+ , cpCreated :: TimeStamp+ , cpCustomer :: CustomerId+ , cpReturnUrl :: Maybe T.Text+ , cpUrl :: T.Text+ } deriving (Show, Eq)++data CustomerPortalCreate+ = CustomerPortalCreate+ { cpcCustomer :: CustomerId+ , cpcReturnUrl :: Maybe T.Text+ } deriving (Show, Eq, Generic)++$(deriveJSON (jsonOpts 2) ''StripeList)+$(deriveJSON (jsonOpts 1) ''Customer)+$(deriveJSON (jsonOpts 1) ''Event)+$(deriveJSON (jsonOpts 2) ''EventData)+$(deriveJSON (jsonOpts 2) ''CheckoutSession)+$(deriveJSON (jsonOpts 1) ''Price)+$(deriveJSON (jsonOpts 2) ''PriceRecurring)+$(deriveJSON (jsonOpts 2) ''Product)+$(deriveJSON (jsonOpts 2) ''CustomerPortal)++instance ToForm CustomerCreate where+ toForm = genericToForm (formOptions 2)++instance ToForm CustomerUpdate where+ toForm = genericToForm (formOptions 2)++instance ToForm CustomerPortalCreate where+ toForm = genericToForm (formOptions 3)++instance ToForm ProductCreate where+ toForm = genericToForm (formOptions 3)++instance ToForm PriceCreate where+ toForm pc =+ let recurringPiece =+ case pcRecurring pc of+ Nothing -> []+ Just x ->+ [ ("recurring[interval]", [prcInterval x])+ , ("recurring[interval_count]", maybeToList $ fmap toUrlPiece $ prcIntervalCount x)+ ]+ in Form $ HM.fromList $+ [ ("currency", [pcCurrency pc])+ , ("product", [toUrlPiece $ pcProduct pc])+ , ("unit_amount", maybeToList $ fmap toUrlPiece $ pcUnitAmount pc)+ , ("lookup_key", maybeToList $ pcLookupKey pc)+ , ("transfer_lookup_key", [toUrlPiece $ pcTransferLookupKey pc])+ ] <> recurringPiece++instance ToForm CheckoutSessionCreate where+ toForm csc =+ let convertItem (idx, itm) =+ [ ("line_items[" <> toUrlPiece idx <> "][price]", [toUrlPiece $ cscliPrice itm])+ , ("line_items[" <> toUrlPiece idx <> "][quantity]", [toUrlPiece $ cscliQuantity itm])+ ]+ lineItems =+ concatMap convertItem (zip ([0..] :: [Int]) (cscLineItems csc))+ convertPmt (idx, pm) =+ ( "payment_method_types[" <> toUrlPiece idx <> "]"+ , [pm]+ )+ pmt =+ map convertPmt (zip ([0..] :: [Int]) (cscPaymentMethodTypes csc))+ in Form $ HM.fromList $+ [ ("cancel_url", [cscCancelUrl csc])+ , ("success_url", [cscSuccessUrl csc])+ , ("mode", [cscMode csc])+ , ("client_reference_id", maybeToList $ cscClientReferenceId csc)+ , ("customer", maybeToList $ fmap toUrlPiece $ cscCustomer csc)+ ] <> lineItems <> pmt
+ src/Stripe/Util/Aeson.hs view
@@ -0,0 +1,16 @@+-- |++module Stripe.Util.Aeson+ ( jsonOpts, deriveJSON, ToJSON, FromJSON )+where++import Data.Aeson+import Data.Aeson.TH+import Text.Casing (quietSnake)++jsonOpts :: Int -> Options+jsonOpts x =+ defaultOptions+ { fieldLabelModifier = quietSnake . drop x+ , constructorTagModifier = quietSnake+ }
+ stripe-servant.cabal view
@@ -0,0 +1,49 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.33.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 44759c17c1b913f08638e1ae86cf9a71e9a090db0772cb4d9da196ae9447d461++name: stripe-servant+version: 0.1.0.0+synopsis: Unofficial Stripe servant types+description: Unofficial description of the Stripe API using servant types+category: Web+homepage: https://github.com/agrafix/stripe-hs#readme+bug-reports: https://github.com/agrafix/stripe-hs/issues+author: Alexander Thiemann <mail@thiemann.at>+maintainer: Alexander Thiemann <mail@thiemann.at>+copyright: 2020 Alexander Thiemann <mail@thiemann.at>+license: BSD3+license-file: LICENSE+build-type: Simple+extra-source-files:+ README.md++source-repository head+ type: git+ location: https://github.com/agrafix/stripe-hs++library+ exposed-modules:+ Stripe.Api+ Stripe.Resources+ Stripe.Util.Aeson+ other-modules:+ Paths_stripe_servant+ hs-source-dirs:+ src+ default-extensions: OverloadedStrings DataKinds TypeOperators TypeFamilies GADTs FlexibleInstances FlexibleContexts MultiParamTypeClasses StrictData ScopedTypeVariables DeriveGeneric DeriveFunctor+ build-depends:+ aeson+ , base >=4.7 && <5+ , casing+ , http-api-data+ , servant+ , text+ , time+ , unordered-containers+ , vector+ default-language: Haskell2010