Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`wreq` Get / Post with exception handling

Tags:

haskell

I am making some http calls using wreq and would like to catch any exception and return an Either type. I tried something like this but could not figure out how to manipulate the calls so it will type check.

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

I am pasting the type error below but I know the above code will not compile. The issue is r <- getWith opts url E.catch handler. The first part returns IO (Res... but the exception handler returns Either... I tried adding lifting the getWith.. into Either but that did not type check 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

Is there a way to catch this exception and return an IO Either type?

like image 336
Ecognium Avatar asked Dec 28 '25 13:12

Ecognium


1 Answers

Since @jozefg answer, the API has changed a little bit and the answer doesn't compile anymore.

Here is an updated version that compiles:

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)
like image 104
vjousse Avatar answered Jan 06 '26 15:01

vjousse



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!