packages feed

hoauth2-0.2.4: src/Network/OAuth2/HTTP/HttpClient.hs

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts   #-}
{-# LANGUAGE OverloadedStrings  #-}

-- | A simple http client for request OAuth2 tokens and several utils.

module Network.OAuth2.HTTP.HttpClient where

import           Control.Applicative        ((<$>))
import           Control.Exception
import           Control.Monad.Trans        (liftIO)
import Control.Monad (liftM)
import           Data.Aeson
import qualified Data.ByteString            as BS
import qualified Data.ByteString.Lazy.Char8 as BSL
import qualified Data.Text                  as T
import qualified Data.Text.Encoding         as T
import           Network.HTTP.Conduit
import           Network.HTTP.Types         (renderSimpleQuery)
import qualified Network.HTTP.Types         as HT

import           Network.OAuth2.OAuth2

--------------------------------------------------

-- | Request (via POST method) "Access Token".
--
--   FIXME: what if @requestAccessToken'@ return error?
--
requestAccessToken :: OAuth2                 -- ^ OAuth Data
                   -> BS.ByteString          -- ^ Authentication code gained after authorization
                   -> IO (Maybe AccessToken) -- ^ Access Token
requestAccessToken oa code = decode <$> doSimplePostRequest (accessTokenUrl oa code)


-- | Request the "Refresh Token".
--
refreshAccessToken :: OAuth2
                   -> BS.ByteString          -- ^ refresh token gained after authorization
                   -> IO (Maybe AccessToken)
refreshAccessToken oa rtoken = decode <$> doSimplePostRequest (refreshAccessTokenUrl oa rtoken)


--------------------------------------------------

-- | Conduct post request.
--
doSimplePostRequest :: (URI, PostBody)       -- ^ The URI and request body for fetching token.
                       -> IO BSL.ByteString  -- ^ Response as ByteString
doSimplePostRequest (uri, body) = doPostRequst (bsToS uri) body >>= handleResponse

-- | Conduct post request and return response as JSON.
-- 
doJSONPostRequest :: FromJSON a
                     => (URI, PostBody)  -- ^ The URI and request body for fetching token.
                     -> IO (Maybe a)     -- ^ Response as ByteString
doJSONPostRequest (uri, body) = doPostRequst (bsToS uri) body
                                >>= liftM decode . handleResponse


-- | Conduct GET request.
--
doSimpleGetRequest :: String                           -- ^ URL
                      -> IO (Response BSL.ByteString)  -- ^ Response as ByteString
doSimpleGetRequest url = liftIO $ withManager $ \man -> do
    req' <- liftIO $ parseUrl url
    httpLbs req' man

-- | Conduct GET request and return response as JSON.
--
doJSONGetRequest :: FromJSON a
                      => String         -- ^ Full URL
                      -> IO (Maybe a)   -- ^ Response as ByteString
doJSONGetRequest url = doGetRequest url []
                         >>= liftM decode . handleResponse

  --liftIO $ withManager $ \man -> do
  --  req' <- liftIO $ parseUrl url
  --  httpLbs req' man


--------------------------------------------------
-- conduit http request
--------------------------------------------------

-- | Conduct GET request with given URL by append extra parameters provided.
--
doGetRequest :: String                               -- ^ URL
                -> [(BS.ByteString, BS.ByteString)]  -- ^ Extra Parameters
                -> IO (Response BSL.ByteString)      -- ^ Response
doGetRequest url pm = liftIO $ withManager $ \man -> do
    req' <- parseUrl $ url ++ bsToS (renderSimpleQuery True pm)
    httpLbs req' man


-- | Conduct POST request with given URL with post body data.
--
doPostRequst ::  String                              -- ^ URL
                -> [(BS.ByteString, BS.ByteString)]  -- ^ Data to Post Body
                -> IO (Response BSL.ByteString)      -- ^ Response
doPostRequst url body = liftIO $ withManager $ \man -> do
    req' <- parseUrl url
    httpLbs (urlEncodedBody body req') man


--------------------------------------------------

handleResponse :: Response BSL.ByteString -> IO BSL.ByteString
handleResponse rsp =  if (HT.statusCode . responseStatus) rsp == 200
                     then return (responseBody rsp)
                     else throwIO . OAuthException $
                          "Gaining token failed: " ++ BSL.unpack (responseBody rsp)


bsToS ::  BS.ByteString -> String
bsToS = T.unpack . T.decodeUtf8

                      --else BSL.putStrLn  "Error rsp" >> return "ERROR"

-- TODO: Control.Exception.try
--        result <- liftIO $ Control.Exception.try $ runResourceT $ httpLbs request man