packages feed

api-monobank 0.1.0.1 → 0.1.1.0

raw patch · 3 files changed

+165/−76 lines, 3 filesdep +http-clientdep +http-client-tlsdep +servant

Dependencies added: http-client, http-client-tls, servant, servant-client

Files

api-monobank.cabal view
@@ -1,5 +1,5 @@ name:                api-monobank-version:             0.1.0.1+version:             0.1.1.0 -- synopsis: description:         Api client for popular Ukrainian bank - Monobank homepage:            https://github.com/sigrlami/api-monobank#readme@@ -24,6 +24,10 @@                      , time                      , http-conduit                      , bytestring+                     , servant+                     , servant-client+                     , http-client+                     , http-client-tls   default-language:    Haskell2010  executable mnb-app@@ -33,6 +37,7 @@   build-depends:       base                      , bytestring                      , http-conduit+                     , http-client                      , aeson                      , stm                      , text
src/Monobank/Api.hs view
@@ -1,33 +1,126 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds                  #-}+{-# LANGUAGE DeriveGeneric              #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE ScopedTypeVariables        #-}+{-# LANGUAGE TemplateHaskell            #-}+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-}  module Monobank.Api     ( getCurrencies-    , getPersonalInfo-    , getPersonalStatement+    , getCurrencyRates'+    , getPersonalInfo'+    , getPersonalStatement'     , getPersonalStatementFull     ) where +import           Control.Applicative+import           Control.Monad+import           Control.Monad.IO.Class import           Data.Aeson import qualified Data.ByteString.Char8      as B import qualified Data.ByteString.Lazy.Char8 as BL+import           Data.Monoid+import           Data.Proxy import qualified Data.Text                  as T+import           GHC.Generics+import           Network.HTTP.Client        (Manager, newManager)+import qualified Network.HTTP.Client        as C+import           Network.HTTP.Client.TLS    (tlsManagerSettings) import           Network.HTTP.Conduit       (simpleHttp)+import qualified Network.HTTP.Simple        as S+import           Servant.API+import           Servant.Client  import           Monobank.Types import           Monobank.Utils  -------------------------------------------------------------------------------- -endpoint :: T.Text-endpoint = "https://api.monobank.ua"+endpoint = "api.monobank.ua" +type MonobankAPI =+       "bank"+    :> "currency"+    :> Get '[JSON] [CurrencyPair]++   -- GET /personal/client-info+  :<|> "personal"+    :> "client-info"+    :> Header "X-Token" T.Text+    :> Get '[JSON] User++  -- GET /personal/statement/{account}/{from}/{to}+  :<|> "personal"+    :> "statement"+    :> Header  "X-Token" T.Text+    :> Capture "account" T.Text+    :> Capture "from"    T.Text+    :> Capture "to"      T.Text+    :> Get '[JSON] Statement++monobankAPI :: Proxy MonobankAPI+monobankAPI = Proxy++-- Derive call functions for the api+getCurrencyRates     :: ClientM [CurrencyPair]+getPersonalInfo      :: Maybe T.Text -> ClientM User+getPersonalStatement :: Maybe T.Text -> T.Text -> T.Text -> T.Text -> ClientM Statement+(     getCurrencyRates+ :<|> getPersonalInfo+ :<|> getPersonalStatement ) = client monobankAPI++--------------------------------------------------------------------------------++-- | Get a basic list of monobank currency rates+-- |+getCurrencyRates' :: IO (Either ServantError [CurrencyPair])+getCurrencyRates' = do+  mgr <- newManager tlsManagerSettings+  let env = ClientEnv mgr host Nothing+  runClientM getCurrencyRates env+  where+    host = (BaseUrl Https endpoint 443 "")++-- | Ger bank user personal information+-- |+getPersonalInfo' :: Maybe T.Text                        -- ^ unique user token+                 -> IO (Either ServantError User)+getPersonalInfo' tkn = do+  mgr <- newManager tlsManagerSettings+  let env = ClientEnv mgr host Nothing+  runClientM (getPersonalInfo tkn) env+  where+    host = (BaseUrl Https endpoint 443 "")+++-- | Receive an extract for the time from {to} to {to} time in seconds Unix time format.+-- | The maximum time for which it is possible to extract an extract is 31 days+-- | (2678400 seconds) Limit on the use of the function no more than 1 time in 60 seconds.+--+getPersonalStatement' :: Maybe T.Text+                      -> T.Text+                      -> T.Text+                      -> T.Text+                      -> IO (Either ServantError Statement)+getPersonalStatement' tkn accM fromM toM = do+  mgr <- newManager tlsManagerSettings+  let env = ClientEnv mgr host Nothing+  runClientM (getPersonalStatement tkn accM fromM toM) env+  where+    host = (BaseUrl Https endpoint 443 "")++--------------------------------------------------------------------------------+ -- Get a basic list of monobank currency rates. -- Information is cached and updated no more than once every 5 minutes. -- -- GET /bank/currency getCurrencies :: IO [CurrencyPair] getCurrencies = do-  let path = T.concat [endpoint, "/bank/currency"]+  let path = T.concat [T.pack endpoint, "/bank/currency"]   -- results <- fmap decodeEither $ simpleHttp (T.unpack path)   resp <- simpleHttp (T.unpack path)   --putStrLn $ show $ resp@@ -38,17 +131,6 @@       return $ []     Right val -> do       return $ val---- GET /personal/client-info-getPersonalInfo = undefined----- Receive an extract for the time from {to} to {to} time in seconds Unix time format.--- The maximum time for which it is possible to extract an extract is 31 days--- (2678400 seconds) Limit on the use of the function no more than 1 time in 60 seconds.------ GET /personal/statement/{account}/{from}/{to}-getPersonalStatement = undefined   -- Get Personal Statement from beginning
src/Monobank/Types.hs view
@@ -18,13 +18,54 @@  import           Monobank.Utils ------------------------------------------------------------------+--------------------------------------------------------------------------------  -- | Wrapper for user token from Developer's Dashboard, https://api.monobank.ua/ type Token = T.Text ------------------------------------------------------------------+data Account =+  Account+    { acId           :: T.Text    -- ^+    , acBalance      :: Int       -- ^ Current balance+    , acCreditLimit  :: Int       -- ^ Current credit limit available to user+    , acCurrencyCode :: Int       -- ^ Currency of the account+    , acCashbackType :: T.Text    -- ^+    } deriving (Eq, Show, Generic) +instance FromJSON Account where+   parseJSON = genericParseJSON opts+     where+       opts = defaultOptions { fieldLabelModifier = uncapFst . drop 2 }++data User =+  User+    { uName     :: T.Text    -- ^ User's full name+    , uAccounts :: [Account] -- ^ List of user accounts, by currency type+    } deriving (Eq, Show)++instance FromJSON User where+  parseJSON =+    withObject "object" $ \o -> do+      nm     <- o .:  "name"+      ac     <- o .:  "accounts"++      return $ User nm ac++data Statement =+  Statement+    { stId              :: String   -- ^+    , stTime            :: String   -- ^+    , stDescription     :: String   -- ^+    , stMCC             :: String   -- ^+    , stHold            :: Bool     -- ^+    , stAmount          :: Int      -- ^+    , stOperationAmount :: Int      -- ^+    , stCurrency        :: Int      -- ^+    , stComissionRate   :: Int      -- ^+    , stCashbackAmount  :: Int      -- ^+    , balance           :: Int      -- ^+    } deriving (Eq, Show, Generic, FromJSON)+ data Currency =   Currency     { isoCode        :: String@@ -34,26 +75,6 @@     , name           :: String     } deriving (Eq, Show) -convertCurrencyFromCode :: Int -> Currency-convertCurrencyFromCode val =-  case val of-    840       ->  Currency { isoCode = "USD", isoNumericCode=  840, decimalDigits= 2, symbol= "$", name="Dollar"}-    978       ->  Currency { isoCode = "EUR", isoNumericCode=  978, decimalDigits= 2, symbol= "€", name="Euro"}-    980       ->  Currency { isoCode = "UAH", isoNumericCode=  980, decimalDigits= 2, symbol= "₴", name="Hrivnya"}-    643       ->  Currency { isoCode = "RUB", isoNumericCode=  643, decimalDigits= 2, symbol= "", name="Ruble"}-    826       ->  Currency { isoCode = "GBP", isoNumericCode=  826, decimalDigits= 2, symbol= "", name="Pound Sterling"}-    949       ->  Currency { isoCode = "TRY", isoNumericCode=  949, decimalDigits= 2, symbol= "", name="Lira"}-    985       ->  Currency { isoCode = "PLN", isoNumericCode=  985, decimalDigits= 2, symbol= "", name="Zloty"}-    348       ->  Currency { isoCode = "HUF", isoNumericCode=  348, decimalDigits= 2, symbol= "", name="Forint"}-    208       ->  Currency { isoCode = "DKK", isoNumericCode=  208, decimalDigits= 2, symbol= "", name="Danish Krone"}-    203       ->  Currency { isoCode = "CZK", isoNumericCode=  203, decimalDigits= 2, symbol= "", name="Czech Koruna"}-    124       ->  Currency { isoCode = "CAD", isoNumericCode=  124, decimalDigits= 2, symbol= "", name="Canadian Dollar"}-    933       ->  Currency { isoCode = "BYN", isoNumericCode=  933, decimalDigits= 2, symbol= "", name="Belarussian Ruble"}-    756       ->  Currency { isoCode = "CHF", isoNumericCode=  756, decimalDigits= 2, symbol= "", name="Swiss Franc"}-    otherwise ->  Currency { isoCode = "NA" , isoNumericCode=  0  , decimalDigits= 2, symbol= "", name="Uknown"}---------------------------------------------------------------------------------------------- -- | Data type that represents currency pair from Monobank --   at spicific time data CurrencyPair =@@ -95,41 +116,22 @@       putStrLn $ " - Sell: " ++ (show $ fromMaybe 0 $ cpRateSell cp) ++ (symbol $ cpCurrencyCodeB cp)       putStrLn $ "" --- Simplified version for one-to-one conversion------ instance FromJSON CurrencyPair where---   parseJSON = genericParseJSON opts---     where---       opts = defaultOptions { fieldLabelModifier = uncapFst . drop 2}- -------------------------------------------------------------------------------- -data Account =-  Account-    { acId           :: T.Text    -- ^-    , acBalance      :: Int       -- ^ Current balance-    , acCreditLimit  :: Int       -- ^ Current credit limit available to user-    , acCurrency     :: Currency  -- ^ Currency of the account-    , acCashbackType :: T.Text    -- ^-    } deriving (Eq, Show)--data User =-  User-    { uName     :: String    -- ^ User's full name-    , uAccounts :: [Account] -- ^ List of user accounts, by currency type-    } deriving (Eq, Show)--data Statement =-  Statement-    { stId              :: String   -- ^-    , stTime            :: String   -- ^-    , stDescription     :: String   -- ^-    , stMCC             :: String   -- ^-    , stHold            :: Bool     -- ^-    , stAmount          :: Int      -- ^-    , stOperationAmount :: Int      -- ^-    , stCurrency        :: Currency -- ^-    , stComissionRate   :: Int      -- ^-    , stCashbackAmount  :: Int      -- ^-    , balance           :: Int      -- ^-    } deriving (Eq, Show)+convertCurrencyFromCode :: Int -> Currency+convertCurrencyFromCode val =+  case val of+    840       ->  Currency { isoCode = "USD", isoNumericCode=  840, decimalDigits= 2, symbol= "$", name="Dollar"}+    978       ->  Currency { isoCode = "EUR", isoNumericCode=  978, decimalDigits= 2, symbol= "€", name="Euro"}+    980       ->  Currency { isoCode = "UAH", isoNumericCode=  980, decimalDigits= 2, symbol= "₴", name="Hrivnya"}+    643       ->  Currency { isoCode = "RUB", isoNumericCode=  643, decimalDigits= 2, symbol= "", name="Ruble"}+    826       ->  Currency { isoCode = "GBP", isoNumericCode=  826, decimalDigits= 2, symbol= "", name="Pound Sterling"}+    949       ->  Currency { isoCode = "TRY", isoNumericCode=  949, decimalDigits= 2, symbol= "", name="Lira"}+    985       ->  Currency { isoCode = "PLN", isoNumericCode=  985, decimalDigits= 2, symbol= "", name="Zloty"}+    348       ->  Currency { isoCode = "HUF", isoNumericCode=  348, decimalDigits= 2, symbol= "", name="Forint"}+    208       ->  Currency { isoCode = "DKK", isoNumericCode=  208, decimalDigits= 2, symbol= "", name="Danish Krone"}+    203       ->  Currency { isoCode = "CZK", isoNumericCode=  203, decimalDigits= 2, symbol= "", name="Czech Koruna"}+    124       ->  Currency { isoCode = "CAD", isoNumericCode=  124, decimalDigits= 2, symbol= "", name="Canadian Dollar"}+    933       ->  Currency { isoCode = "BYN", isoNumericCode=  933, decimalDigits= 2, symbol= "", name="Belarussian Ruble"}+    756       ->  Currency { isoCode = "CHF", isoNumericCode=  756, decimalDigits= 2, symbol= "", name="Swiss Franc"}+    otherwise ->  Currency { isoCode = "NA" , isoNumericCode=  0  , decimalDigits= 2, symbol= "", name="Uknown"}