I'm trying to build a Haskell client to consume a RESTful JSON API. I want to fetch a page, then take the "next_page" key from the response, and feed it into the query params of another api request. I want to continue doing this until I have paged through all the items. What is the cleanest way of doing this in Haskell? I'm using explicit recursion now, but I feel there must be a better way, maybe with the writer or state monad.
EDIT: Added my code. I'm aware I'm misusing fromJust.
data Post = Post {
title :: !Text,
domain :: !Text,
score :: Int,
url :: !Text
} deriving (Show)
instance FromJSON Post where
parseJSON (Object v) = do
objectData <- v .: "data"
title <- objectData .: "title"
domain <- objectData .: "domain"
score <- objectData .: "score"
url <- objectData .: "url"
return $ Post title domain score url
data GetPostsResult = GetPostsResult {
posts :: [Post],
after :: Maybe Text
} deriving (Show)
instance FromJSON GetPostsResult where
parseJSON (Object v) = do
rootData <- v .: "data"
posts <- rootData .: "children"
afterCode <- rootData .:? "after"
return $ GetPostsResult posts afterCode
fetchPage:: Text -> IO (Maybe ([Post],Maybe Text))
fetchPage afterCode = do
let url = "https://www.reddit.com/r/videos/top/.json?sort=top&t=day&after=" ++ unpack afterCode
b <- get url
let jsonBody = b ^. responseBody
let postResponse = decode jsonBody :: Maybe GetPostsResult
let pagePosts = posts <$> postResponse
let nextAfterCode = after $ fromJust postResponse
if isNothing pagePosts then return Nothing else return (Just (fromJust pagePosts,nextAfterCode))
getPosts :: Text -> [Post] -> IO [Post]
getPosts x y = do
p <- liftIO $ fetchPage x
let posts = fst (fromJust p)
let afterParam = snd (fromJust p)
case afterParam of
Nothing -> return []
Just aff -> getPosts aff (posts ++ y)
main = do
a <- getPosts "" []
print a