{-# LANGUAGE OverloadedStrings #-} module Mollie.API.Internal where import qualified Control.Monad.Reader as Reader import qualified Data.Aeson as Aeson import qualified Data.ByteString.Lazy as ByteString import Data.Monoid import qualified Data.Text as Text import qualified Data.Text.Encoding as Text import Mollie.API.Types import qualified Network.HTTP.Client as HTTP import qualified Network.HTTP.Types as HTTP {-| Environment to run requests to Mollie with. -} data Env = Env { env_key :: Text.Text , env_manager :: HTTP.Manager } {-| Reader wrapper with Mollie Env. -} type Mollie a = Reader.ReaderT Env IO a endpoint :: Text.Text endpoint = "https://api.mollie.nl" version :: Text.Text version = "v1" showT :: (Show a) => a -> Text.Text showT = Text.pack . show initialRequest :: Text.Text -> Mollie (HTTP.Request) initialRequest path = do api_key <- Reader.asks env_key request <- HTTP.parseRequest . Text.unpack $ Text.intercalate "/" [endpoint, version, path] return request { HTTP.requestHeaders = [ ("Authorization", Text.encodeUtf8 $ "Bearer " <> api_key) , ("Accept", "application/json") ] } execute :: HTTP.Request -> Mollie (Either ResponseError (Int, ByteString.ByteString)) execute request = do manager <- Reader.asks env_manager response <- Reader.liftIO $ HTTP.httpLbs request manager return $ handleStatus (HTTP.statusCode $ HTTP.responseStatus response) (HTTP.responseBody response) where handleStatus status body | elem status [200, 201, 204] = Right (status, body) | elem status [400, 401, 403, 404, 405, 415, 422, 429] = case Aeson.decode body of Just err -> Left $ ClientError status err Nothing -> Left UnexpectedResponse | elem status [500, 502, 503, 504] = Left $ ServerError status | otherwise = Left UnexpectedResponse send :: (Aeson.ToJSON a) => HTTP.Method -> Text.Text -> a -> Mollie (Either ResponseError (Int, ByteString.ByteString)) send method url reqBody = do request <- initialRequest url execute request { HTTP.method = method , HTTP.requestBody = HTTP.RequestBodyLBS $ Aeson.encode reqBody } get :: (Aeson.FromJSON a) => Text.Text -> Mollie (Either ResponseError a) get url = do request <- initialRequest url result <- execute request return $ decodeResult result delete :: Text.Text -> Mollie (Either ResponseError (Int, ByteString.ByteString)) delete url = do request <- initialRequest url execute request { HTTP.method = HTTP.methodDelete } ignoreResult :: Either ResponseError (Int, ByteString.ByteString) -> Maybe ResponseError ignoreResult result = case result of Right _ -> Nothing Left err -> Just err decodeResult :: (Aeson.FromJSON a) => Either ResponseError (Int, ByteString.ByteString) -> Either ResponseError a decodeResult result = case result of Right (_, body) -> case Aeson.decode body of Just resource -> Right resource Nothing -> Left UnexpectedResponse Left other -> Left other