{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE EmptyCase #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} module Main where import Data.Char (toLower) import Data.Proxy (Proxy(Proxy)) import Network.Wai (Application) import Network.Wai.Handler.Warp (run) import Servant (Handler, (:<|>)((:<|>)), ServerT, serve) import Servant.Checked.Exceptions (Envelope, pureErrEnvelope, pureSuccEnvelope) import Api ( Api , BadSearchTermErr(BadSearchTermErr) , IncorrectCapitalization(IncorrectCapitalization) , SearchQuery(SearchQuery) , SearchResponse , port ) -- | This is our server root for the 'ServerT' for 'Api'. We only have two -- handlers, 'postStrictSearch' and 'postLaxSearch'. serverRoot :: ServerT Api Handler serverRoot = postStrictSearch :<|> postLaxSearch :<|> postNoErrSearch -- | This is the handler for 'Api.ApiStrictSearch'. -- -- If we get the 'SearchQuery' @\"Hello\"@, we return a 'SuccEnvelope'. -- However, if we get a search query like @\"hello\"@, we return an -- 'ErrEnvelope' with an 'IncorrectCapitialization' error. If we get a search -- query that is not @\"hello\"@, we return an 'ErrEnvelope' with a -- 'BadSearchTermErr'. -- -- Notice how we can use the polymorphic function 'pureErrEnvelope' to return -- either an 'IncorrectCapitialization' error, or a 'BadSearchTermErr', even -- though these two have different types. -- -- Also, notice how this function returns an 'Envelope' because we are using -- 'Throws' in the api definition. postStrictSearch :: SearchQuery -> Handler (Envelope '[BadSearchTermErr, IncorrectCapitalization] SearchResponse) postStrictSearch (SearchQuery "Hello") = pureSuccEnvelope "good" postStrictSearch (SearchQuery query) | fmap toLower query == "hello" = pureErrEnvelope IncorrectCapitalization | otherwise = pureErrEnvelope BadSearchTermErr -- | This is the handler for 'Api.ApiLaxSearch'. -- -- This is similar to 'postStrictSearch', but it doesn't require correct -- capitalization. postLaxSearch :: SearchQuery -> Handler (Envelope '[BadSearchTermErr] SearchResponse) postLaxSearch (SearchQuery query) | fmap toLower query == "hello" = pureSuccEnvelope "good" | otherwise = pureErrEnvelope BadSearchTermErr -- | This is the handler for 'Api.ApiNoErrSearch'. -- -- This is similar to 'postLaxSearch', but it doesn't require a correct search -- term. postNoErrSearch :: SearchQuery -> Handler (Envelope '[] SearchResponse) postNoErrSearch (SearchQuery _) = pureSuccEnvelope "good" -- | Create a WAI 'Application'. app :: Application app = serve (Proxy :: Proxy Api) serverRoot -- | Run the WAI 'Application' using 'run' on the port defined by 'port'. main :: IO () main = run port app