module Web.HackerNews
(
HackerNewsAPI
, HackerCapture
, getItem
, getUser
, getMaxItem
, getTopStories
, getNewStories
, getBestStories
, getAskStories
, getShowStories
, getJobStories
, getUpdates
, Item (..)
, User (..)
, Updates (..)
, MaxItem (..)
, TopStories (..)
, NewStories (..)
, BestStories (..)
, AskStories (..)
, ShowStories (..)
, JobStories (..)
, UserId (..)
, ItemId (..)
, Deleted (..)
, ItemType (..)
, UserName (..)
, Time (..)
, ItemText (..)
, Dead (..)
, Parent (..)
, Kids (..)
, URL (..)
, Score (..)
, Title (..)
, Parts (..)
, Descendants (..)
, Delay (..)
, Created (..)
, Karma (..)
, About (..)
, Submitted (..)
, HackerNewsError (..)
) where
import Control.Monad.Trans.Except
import Data.Bifunctor
import Data.Monoid
import Data.Proxy
import Data.String.Conversions
import qualified Data.Text as T
import Network.HTTP.Client (Manager)
import Network.HTTP.Types.Status
import Servant.API
import Servant.Client
import Servant.Common.Req
import Web.HackerNews.Types
type HackerNewsAPI =
"item" :> HackerCapture ItemId :> Get '[JSON] Item
:<|> "user" :> HackerCapture UserId :> Get '[JSON] User
:<|> "maxitem.json" :> Get '[JSON] MaxItem
:<|> "topstories.json" :> Get '[JSON] TopStories
:<|> "newstories.json" :> Get '[JSON] NewStories
:<|> "beststories.json" :> Get '[JSON] BestStories
:<|> "askstories.json" :> Get '[JSON] AskStories
:<|> "showstories.json" :> Get '[JSON] ShowStories
:<|> "jobstories.json" :> Get '[JSON] JobStories
:<|> "updates.json" :> Get '[JSON] Updates
data HackerCapture (a :: *)
instance (ToHttpApiData a, HasClient api) => HasClient (HackerCapture a :> api) where
type Client (HackerCapture a :> api) = a -> Client api
clientWithRoute Proxy req val =
clientWithRoute (Proxy :: Proxy api)
(appendToPath p req)
where
p = T.unpack $ toUrlPiece val <> ".json"
hackerNewsURL :: BaseUrl
hackerNewsURL = BaseUrl Https "hacker-news.firebaseio.com" 443 "/v0"
toError :: Either ServantError ok -> Either HackerNewsError ok
toError = first go
where
go :: ServantError -> HackerNewsError
go (FailureResponse Status{..} _ body) =
FailureResponseError statusCode (cs statusMessage) (cs body)
go (DecodeFailure _ _ "null") = NotFound
go (DecodeFailure err _ body) =
DecodeFailureError (cs err) (cs body)
go (UnsupportedContentType _ body) =
UnsupportedContentTypeError (cs body)
go (InvalidContentTypeHeader header body) =
InvalidContentTypeHeaderError (cs header) (cs body)
go (ConnectionError ex) =
HNConnectionError $ cs (show ex)
getItem :: Manager -> ItemId -> IO (Either HackerNewsError Item)
getItem mgr itemId =
toError <$> do
runExceptT $ getItem' itemId mgr hackerNewsURL
getUser :: Manager -> UserId -> IO (Either HackerNewsError User)
getUser mgr userId =
toError <$> do
runExceptT $ getUser' userId mgr hackerNewsURL
getMaxItem :: Manager -> IO (Either HackerNewsError MaxItem)
getMaxItem mgr =
toError <$> do
runExceptT $ getMaxItem' mgr hackerNewsURL
getTopStories :: Manager -> IO (Either HackerNewsError TopStories)
getTopStories mgr =
toError <$> do
runExceptT $ getTopStories' mgr hackerNewsURL
getNewStories :: Manager -> IO (Either HackerNewsError NewStories)
getNewStories mgr =
toError <$> do
runExceptT $ getNewStories' mgr hackerNewsURL
getBestStories :: Manager -> IO (Either HackerNewsError BestStories)
getBestStories mgr =
toError <$> do
runExceptT $ getBestStories' mgr hackerNewsURL
getAskStories :: Manager -> IO (Either HackerNewsError AskStories)
getAskStories mgr =
toError <$> do
runExceptT $ getAskStories' mgr hackerNewsURL
getShowStories :: Manager -> IO (Either HackerNewsError ShowStories)
getShowStories mgr =
toError <$> do
runExceptT $ getShowStories' mgr hackerNewsURL
getJobStories :: Manager -> IO (Either HackerNewsError JobStories)
getJobStories mgr =
toError <$> do
runExceptT $ getJobStories' mgr hackerNewsURL
getUpdates :: Manager -> IO (Either HackerNewsError Updates)
getUpdates mgr =
toError <$> do
runExceptT $ getUpdates' mgr hackerNewsURL
getItem' :: ItemId -> Manager -> BaseUrl -> ClientM Item
getUser' :: UserId -> Manager -> BaseUrl -> ClientM User
getMaxItem' :: Manager -> BaseUrl -> ClientM MaxItem
getTopStories' :: Manager -> BaseUrl -> ClientM TopStories
getNewStories' :: Manager -> BaseUrl -> ClientM NewStories
getBestStories' :: Manager -> BaseUrl -> ClientM BestStories
getAskStories' :: Manager -> BaseUrl -> ClientM AskStories
getShowStories' :: Manager -> BaseUrl -> ClientM ShowStories
getJobStories' :: Manager -> BaseUrl -> ClientM JobStories
getUpdates' :: Manager -> BaseUrl -> ClientM Updates
getItem'
:<|> getUser'
:<|> getMaxItem'
:<|> getTopStories'
:<|> getNewStories'
:<|> getBestStories'
:<|> getAskStories'
:<|> getShowStories'
:<|> getJobStories'
:<|> getUpdates' = client (Proxy :: Proxy HackerNewsAPI)