{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE EmptyCase #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} module Main where import Data.Monoid ((<>)) import Data.Proxy (Proxy(Proxy)) import Network.HTTP.Client (defaultManagerSettings, newManager) import Options.Applicative (Parser, (<**>), argument, execParser, fullDesc, help, helper, info, long, metavar, progDesc, short, str, switch) import Servant.API ((:<|>)((:<|>))) import Servant.Client (BaseUrl(BaseUrl), ClientEnv(ClientEnv), ClientM, Scheme(Http), client, runClientM) import Servant.Checked.Exceptions (Envelope, catchesEnvelope) import Api (Api, BadSearchTermErr(BadSearchTermErr), IncorrectCapitalization(IncorrectCapitalization), SearchQuery(SearchQuery), SearchResponse(SearchResponse), port) strictSearch :: SearchQuery -> ClientM (Envelope '[BadSearchTermErr, IncorrectCapitalization] SearchResponse) laxSearch :: SearchQuery -> ClientM (Envelope '[BadSearchTermErr] SearchResponse) strictSearch :<|> laxSearch = client (Proxy :: Proxy Api) data Options = Options { query :: String, useStrict :: Bool } queryParser :: Parser String queryParser = argument str (metavar "QUERY") useStrictParser :: Parser Bool useStrictParser = switch $ long "strict" <> short 's' <> help "Whether to be use the strict api" commandParser :: Parser Options commandParser = Options <$> queryParser <*> useStrictParser runStrict :: ClientEnv -> String -> IO () runStrict clientEnv query = do eitherRes <- runClientM (strictSearch $ SearchQuery query) clientEnv case eitherRes of Left servantErr -> putStrLn $ "Got a ServantErr: " <> show servantErr Right env -> putStrLn $ catchesEnvelope ( \BadSearchTermErr -> "the search term was not \"Hello\"" , \IncorrectCapitalization -> "the search term was not capitalized correctly" ) (\(SearchResponse searchResponse) -> "Success: " <> searchResponse) env runLax :: ClientEnv -> String -> IO () runLax clientEnv query = do eitherRes <- runClientM (laxSearch $ SearchQuery query) clientEnv case eitherRes of Left servantErr -> putStrLn $ "Got a ServantErr: " <> show servantErr Right env -> putStrLn $ catchesEnvelope (\BadSearchTermErr -> "the search term was not \"Hello\"") (\(SearchResponse searchResponse) -> "Success: " <> searchResponse) env run :: ClientEnv -> Options -> IO () run clientEnv Options{query, useStrict = True} = runStrict clientEnv query run clientEnv Options{query, useStrict = False} = runLax clientEnv query main :: IO () main = do manager <- newManager defaultManagerSettings let clientEnv = ClientEnv manager baseUrl options <- execParser opts run clientEnv options where opts = info (commandParser <**> helper) $ fullDesc <> progDesc "Send the QUERY to the example server and print the response." baseUrl :: BaseUrl baseUrl = BaseUrl Http "localhost" port ""