2016-04-01 6 views
3

wreqを使用してhttpコールを行っていますが、例外をキャッチしてEitherタイプを返したいと思います。私はこのようなことを試しましたが、コールを操作する方法を理解できなかったため、タイプチェックが行われます。`wreq`例外処理の取得/ポスト

-- exhaustive pattern match omitted here 
safeGetUrl :: URL -> Maybe Login -> Maybe Password -> IO (Either String (Response LBS.ByteString)) 
safeGetUrl url (Just login) (Just pass) = do 
    let def = defaults 
     opts = def & auth ?~ basicAuth (BS.pack login) (BS.pack pass) 
    r <- getWith opts url `E.catch` handler 
    return $ Right r 

    where 
    handler :: HttpException -> Either String (Response LBS.ByteString) 
    handler (StatusCodeException s _ _) = do 
      return $ Left $ LBS.unpack (s ^. statusMessage) 

以下のタイプのエラーを貼り付けていますが、上記のコードはコンパイルされません。問題はr <- getWith opts urlE.catchhandlerです。最初の部分はIO (Res...を返しますが、例外ハンドラはEither..を返します。私はをEitherに持ち上げようとしましたが、タイプチェックもしませんでした。

Couldn't match type ‘Either String (Response LBS.ByteString)’ 
       with ‘IO (Response LBS.ByteString)’ 
    Expected type: HttpException -> IO (Response LBS.ByteString) 
    Actual type: HttpException 
       -> Either String (Response LBS.ByteString) 
    In the second argument of ‘catch’, namely ‘handler’ 
    In a stmt of a 'do' block: r <- getWith opts url `catch` handler 

IO Eitherタイプをこの例外をキャッチし、返却する方法はありますか?

答えて

4

ハンドルの一方の側がアンラップされた応答(Either)を返し、もう一方の側がEither - ラップされた例外を返します。あなたはそれを行う必要があるEitherで応答をラップしようとしますが、間違った場所にあるだけです。あなたはunpackが戻っWord8のないCharを与えることを覚えて、しかし、あなたの機能を持つ他のいくつかの問題があるあなたが

safeGetUrl :: URL -> Maybe Login -> Maybe Password -> IO (Either String (Response LBS.ByteString)) 
safeGetUrl url (Just login) (Just pass) = do 
    let def = defaults 
     opts = def & auth ?~ basicAuth (BS.pack login) (BS.pack pass) 
    (Right <$> getWith opts url) `E.catch` handler 

    where 
    handler :: HttpException -> IO (Either String (Response LBS.ByteString)) 
    handler (StatusCodeException s _ _) = do 
      return $ Left $ LBS.unpack (s ^. statusMessage) 

を包むんどこ切り替えるだけでこの問題を解決することができます。 unpackのバージョンがLBS.unpackより良く動作するように定義されているので、Data.ByteString.Charをインポートすることができます。あなたの輸入がなければ、私はこれを確実に確認することはできません。私にとっての最終的なコードは、

import Control.Lens 
import Network.Wreq 
import Network.HTTP.Client 
import qualified Control.Exception as E 
import qualified Data.ByteString.Char8 as BSC 
import qualified Data.ByteString.Lazy as LBS 

type URL = String 
type Login = String 
type Password = String 

safeGetUrl :: URL 
      -> Maybe Login 
      -> Maybe Password 
      -> IO (Either String (Response LBS.ByteString)) 
safeGetUrl url (Just login) (Just pass) = do 
    let def = defaults 
     opts = def & auth ?~ basicAuth (BSC.pack login) (BSC.pack pass) 
    (Right <$> getWith opts url) `E.catch` handler 
    where 
    handler :: HttpException -> IO (Either String (Response LBS.ByteString)) 
    handler (StatusCodeException s _ _) = do 
     return $ Left $ BSC.unpack (s ^. statusMessage) 
+0

ありがとう:ここ

はコンパイル更新されたバージョンです。私は 'getWith'を「持ち上げ」しようとしていましたが、何とかそれをやる方法を理解できませんでした。私はまだHaskellの初心者の段階にありますので、ただちに '<$>'を使ってどのように応答を包み込むことができないのかを直ちに知ることはできませんでした。 「BSC」対「LBS」については、それはそれを指摘してくれてありがとうございました。 – Ecognium

0

です。@jozefgが答えて以来、APIは少し変更されており、答えはもうコンパイルされません。

import qualified Control.Exception  as E 
import   Control.Lens 
import qualified Data.ByteString.Char8 as BSC 
import qualified Data.ByteString.Lazy as LBS 
import   Network.HTTP.Client 
import   Network.Wreq   as NW 

type URL = String 

type Login = String 

type Password = String 

safeGetUrl :: 
    URL 
    -> Maybe Login 
    -> Maybe Password 
    -> IO (Either String (Response LBS.ByteString)) 
safeGetUrl url (Just login) (Just pass) = do 
    let def = defaults 
     opts = def & auth ?~ basicAuth (BSC.pack login) (BSC.pack pass) 
    (Right <$> getWith opts url) `E.catch` handler 
    where 
    handler :: HttpException -> IO (Either String (Response LBS.ByteString)) 
    handler (HttpExceptionRequest _ (StatusCodeException r _)) = 
     return $ Left $ BSC.unpack (r ^. NW.responseStatus . statusMessage)