{-# 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
data Env = Env
{ env_key :: Text.Text
, env_manager :: HTTP.Manager
}
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