2016-04-01 11 views
3

Ich mache einige http Anrufe mit wreq und möchte irgendeine Ausnahme fangen und einen Either Typ zurückgeben. Ich habe so etwas versucht, aber ich konnte nicht herausfinden, wie man die Anrufe manipuliert, damit es check eingibt.`wreq` Get/Post mit Ausnahmebehandlung

-- 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) 

Ich bin den Typ Fehler unten einfügen, aber ich weiß, der obige Code wird nicht kompilieren. Das Problem ist r <- getWith opts urlE.catchhandler. Der erste Teil gibt IO (Res... zurück, aber der Ausnahmebehandler gibt Either.. zurück. Ich versuchte, die getWith.. in Either anhebend, aber das prüfte auch nicht.

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 

Gibt es eine Möglichkeit, diese Ausnahme zu fangen und zurück einen IO Either Typen?

Antwort

4

Ihr Problem ist, dass eine Seite des Griffs eine unverpackte Antwort zurückgibt (keine Either) und die andere Seite eine Either -wrapped Ausnahme zurückgibt. Sie versuchen dann, die Antwort in eine Either umzubrechen, die Sie tun müssen, aber es ist nur an der falschen Stelle. Sie können dies nur beheben, indem Schalt wo Sie die

Einwickeln
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) 

Es gibt jedoch einige andere Probleme mit Ihrem Funktionen, denken Sie daran, dass unpack gibt zurück Word8 s nicht Char. Möglicherweise möchten Sie Data.ByteString.Char importieren, da die dort definierte Version unpack besser funktionieren sollte als LBS.unpack. Ohne Ihre Importe kann ich dies jedoch nicht definitiv bestätigen. Der letzte (in Betrieb) Code für mich ist

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

Danke. Ich habe versucht, 'getWith' zu heben und irgendwie konnte ich nicht herausfinden, wie es geht. Ich bin immer noch im Anfängerstadium in Haskell, also habe ich nicht sofort gesehen, wie ich einfach '<$>' verwenden kann, um die Antwort in "Entweder" zu verpacken. In Bezug auf die "BSC" vs. "LBS" ... war das ein Versehen meinerseits - danke, dass du es aufgezeigt hast. – Ecognium

0

Seit @jozefg Antwort, die API ein wenig und die Antwort nicht mehr kompiliert geändert hat. Hier

ist eine aktualisierte Version, die kompiliert:

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)