Question

Using http-conduit I want to download a HTTP URL implementing the following semantics (resulting in IO (Maybe LB.ByteString) ):

  1. If the HTTP response code is 2xx, return Just the response body
  2. If the HTTP response code is 404, return Nothing
  3. If the response code indicates a redirect, follow according to standard http-conduit settings
  4. For any other response code, throw a StatusCodeException.

How can I do that using httpLbs without any libraries beyond http-conduit and its dependencies?

Note: This question was answered in Q&A form and therefore intentionally does not show research effort.

Was it helpful?

Solution

This is possible by using a custom checkStatus similar to one of the offical examples.

We will declare checkStatus200 which passes if the response status code is either 2xx or 404. If it doesn't pass, it calls the default checkStatus function to throw the appropriate exception.

After calling httpLbs with a Request using checkStatus200, we can check the status code and return either Just the response code or Nothing.

import Data.Conduit.Binary (sinkFile)
import Network.HTTP.Types.Status (Status(..))
import Network.HTTP.Conduit
import qualified Data.Conduit as C
import Network
import Data.Default (def)
import qualified Data.ByteString.Lazy as LB

-- | @checkStatus@ implementation that accepts 
--   2xx status codes and 404. Calls default implementation
--   on other status codes (i.e. throws exception)
checkStatus200 st@(Status sc _) rh cj =
    if (200 <= sc && sc < 300) || sc == 404
        then Nothing
        else (checkStatus def) st rh cj

-- | Download a HTTP link, returning @Nothing@ on 404 status code
downloadCatch404 :: String
                 -> IO (Maybe LB.ByteString)
downloadCatch404 url = withSocketsDo $ do
    request <- parseUrl url
    let request' = request { checkStatus = checkStatus200 }
    res <- withManager $ httpLbs request'
    let status =  statusCode . responseStatus $ res
    -- Return Nothing if status code == 404
    return $ if status == 404
        then Nothing
        else Just $ responseBody res
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top