trivelt
trivelt

Reputation: 1965

How to process HttpResponseBody in Haskell req?

I have an application that gets JSON response from an API and I'm trying to get a specific key from that response. The working code looks as below:

{-# LANGUAGE OverloadedStrings #-}

module Main (main) where
import Data.Aeson
import Network.HTTP.Req
   
tinyUIDRequest :: String -> Req (JsonResponse Object)
tinyUIDRequest url = let payload = object [ "url" .= url ] 
                 in req 
                    POST 
                    (https "tinyuid.com" /: "api" /: "v1" /: "shorten") (
                    ReqBodyJson payload) 
                    jsonResponse
                    mempty           

main :: IO ()
main = do 
    response <- runReq defaultHttpConfig (tinyUIDRequest "http://google.com")
    let body = responseBody response
    print body

And the function to process the response should look similar to:

tinyUIDResponseHandler :: HttpResponseBody (JsonResponse Object) -> String
tinyUIDResponseHandler r = case lookup "result_url" r of 
                            Just url -> url
                            Nothing -> ""

unfortunately I'm not able to figure out how to transform HttpResponseBody (JsonResponse Object) to something like hashmap/list and find a proper key. I was checking the documentation and req source code but maybe, as a beginner in Haskell, I don't know exactly what to look for to understand the internals of the response type.

Upvotes: 0

Views: 303

Answers (1)

HttpResponseBody is a red herring. It's an associated type, and HttpResponseBody (JsonResponse a) is the same as just a, so HttpResponseBody (JsonResponse Object) is really just Object. As such, once you have body, req's job is done, and it's now just aeson that you need to be concerned with.

Since body is an Object and not a list of tuples, you can't use Prelude's lookup on it. If your Aeson version is older than 2, then Object is just HashMap Text Value, so do this instead:

import Data.Text
import qualified Data.HashMap.Strict as HM

tinyUIDResponseHandler :: Object -> Text
tinyUIDResponseHandler r = case HM.lookup "result_url" r of 
                            Just (String url) -> url
                            _ -> ""

If your Aeson version is 2 or newer, then Object is KeyMap Value, so do this instead:

import Data.Text
import qualified Data.Aeson.KeyMap as AKM

tinyUIDResponseHandler :: Object -> Text
tinyUIDResponseHandler r = case AKM.lookup "result_url" r of 
                            Just (String url) -> url
                            _ -> ""

In either case, tinyUIDResponseHandler body will then be the value you want, so for example, you could do print (tinyUIDResponseHandler body).

Upvotes: 4

Related Questions