@@ -0,0 +1,83 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE DeriveGeneric #-}
3+{-# LANGUAGE TypeOperators #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+import Control.Applicative
7+import Control.Monad.IO.Class
8+import Control.Monad.Trans.Either
12+import Data.Text (Text)
17+import qualified Data.Text as T
18+import qualified Data.Text.IO as T
21+ "users" :> Get '[JSON] [UserSummary]
22+ :<|> "user" :> Capture "username" Username :> Get '[JSON] UserDetailed
23+ :<|> "packages" :> Get '[JSON] [Package]
27+data UserSummary = UserSummary
28+ { summaryUsername :: Username
29+ , summaryUserid :: Int
30+ } deriving (Eq, Show)
32+instance FromJSON UserSummary where
33+ parseJSON (Object o) =
34+ UserSummary <$> o .: "username"
41+data UserDetailed = UserDetailed
42+ { username :: Username
45+ } deriving (Eq, Show, Generic)
47+instance FromJSON UserDetailed
49+newtype Package = Package { packageName :: Text }
50+ deriving (Eq, Show, Generic)
52+instance FromJSON Package
54+hackageAPI :: Proxy HackageAPI
57+getUsers :: BaseUrl -> EitherT ServantError IO [UserSummary]
58+getUser :: Username -> BaseUrl -> EitherT ServantError IO UserDetailed
59+getPackages :: BaseUrl -> EitherT ServantError IO [Package]
60+getUsers :<|> getUser :<|> getPackages = client hackageAPI
62+run :: (BaseUrl -> r) -> r
63+run f = f (BaseUrl Http "hackage.haskell.org" 80)
66+main = print =<< uselessNumbers
68+uselessNumbers :: IO (Either ServantError ())
69+uselessNumbers = runEitherT $ do
70+ users <- run getUsers
71+ liftIO . putStrLn $ show (length users) ++ " users"
74+ putStrLn "Enter a valid hackage username"
76+ userDetailed <- run (getUser user)
77+ liftIO . T.putStrLn $ user <> " maintains " <> T.pack (show (length $ groups userDetailed)) <> " packages"
79+ packages <- run getPackages
80+ let monadPackages = filter (isMonadPackage . packageName) packages
81+ liftIO . putStrLn $ show (length monadPackages) ++ " monad packages"
83+ where isMonadPackage = T.isInfixOf "monad"