@@ -1,23 +1,22 @@
1−{-# LANGUAGE CPP #-}
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2{-# LANGUAGE ConstraintKinds #-}
2{-# LANGUAGE ConstraintKinds #-}
3{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE DataKinds #-}
4{-# LANGUAGE DeriveDataTypeable #-}
4{-# LANGUAGE DeriveDataTypeable #-}
5{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE FlexibleContexts #-}
6{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE FlexibleInstances #-}
7+{-# LANGUAGE InstanceSigs #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE PolyKinds #-}
10{-# LANGUAGE PolyKinds #-}
11+{-# LANGUAGE QuantifiedConstraints #-}
10{-# LANGUAGE RankNTypes #-}
12{-# LANGUAGE RankNTypes #-}
11{-# LANGUAGE ScopedTypeVariables #-}
13{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE TupleSections #-}
14{-# LANGUAGE TupleSections #-}
15+{-# LANGUAGE TypeApplications #-}
13{-# LANGUAGE TypeFamilies #-}
16{-# LANGUAGE TypeFamilies #-}
14{-# LANGUAGE TypeOperators #-}
17{-# LANGUAGE TypeOperators #-}
15{-# LANGUAGE UndecidableInstances #-}
18{-# LANGUAGE UndecidableInstances #-}
17−#if MIN_VERSION_base(4,9,0) && __GLASGOW_HASKELL__ >= 802
18−#define HAS_TYPE_ERROR
21module Servant.Server.Internal
20module Servant.Server.Internal
22 ( module Servant.Server.Internal
21 ( module Servant.Server.Internal
23 , module Servant.Server.Internal.BasicAuth
22 , module Servant.Server.Internal.BasicAuth
@@ -42,6 +41,7 @@ import qualified Data.ByteString as B
42import qualified Data.ByteString.Builder as BB
41import qualified Data.ByteString.Builder as BB
43import qualified Data.ByteString.Char8 as BC8
42import qualified Data.ByteString.Char8 as BC8
44import qualified Data.ByteString.Lazy as BL
43import qualified Data.ByteString.Lazy as BL
44+import Data.Constraint (Dict(..))
45import Data.Either
45import Data.Either
46 (partitionEithers)
46 (partitionEithers)
47import Data.Maybe
47import Data.Maybe
@@ -54,6 +54,7 @@ import Data.Tagged
54 (Tagged (..), retag, untag)
54 (Tagged (..), retag, untag)
55import qualified Data.Text as T
55import qualified Data.Text as T
56import Data.Typeable
56import Data.Typeable
57import GHC.TypeLits
58import GHC.TypeLits
58 (KnownNat, KnownSymbol, natVal, symbolVal)
59 (KnownNat, KnownSymbol, natVal, symbolVal)
59import qualified Network.HTTP.Media as NHM
60import qualified Network.HTTP.Media as NHM
@@ -75,7 +76,8 @@ import Servant.API
75 QueryParam', QueryParams, Raw, ReflectMethod (reflectMethod),
76 QueryParam', QueryParams, Raw, ReflectMethod (reflectMethod),
76 RemoteHost, ReqBody', SBool (..), SBoolI (..), SourceIO,
77 RemoteHost, ReqBody', SBool (..), SBoolI (..), SourceIO,
77 Stream, StreamBody', Summary, ToSourceIO (..), Vault, Verb,
78 Stream, StreamBody', Summary, ToSourceIO (..), Vault, Verb,
78− WithNamedContext)
79+ WithNamedContext, NamedRoutes)
80+import Servant.API.Generic (GenericMode(..), ToServant, ToServantApi, GServantProduct, toServant, fromServant)
79import Servant.API.ContentTypes
81import Servant.API.ContentTypes
80 (AcceptHeader (..), AllCTRender (..), AllCTUnrender (..),
82 (AcceptHeader (..), AllCTRender (..), AllCTUnrender (..),
81 AllMime, MimeRender (..), MimeUnrender (..), NoContent,
83 AllMime, MimeRender (..), MimeUnrender (..), NoContent,
@@ -101,12 +103,10 @@ import Servant.Server.Internal.RouteResult
101import Servant.Server.Internal.RoutingApplication
103import Servant.Server.Internal.RoutingApplication
102import Servant.Server.Internal.ServerError
104import Servant.Server.Internal.ServerError
104−#ifdef HAS_TYPE_ERROR
105import GHC.TypeLits
106import GHC.TypeLits
106 (ErrorMessage (..), TypeError)
107 (ErrorMessage (..), TypeError)
107import Servant.API.TypeLevel
108import Servant.API.TypeLevel
108 (AtLeastOneFragment, FragmentUnique)
109 (AtLeastOneFragment, FragmentUnique)
111class HasServer api context where
111class HasServer api context where
112 type ServerT api (m :: * -> *) :: *
112 type ServerT api (m :: * -> *) :: *
@@ -784,7 +784,7 @@ instance ( KnownSymbol realm
784-- * helpers
784-- * helpers
786ct_wildcard :: B.ByteString
786ct_wildcard :: B.ByteString
787−ct_wildcard = "*" <> "/" <> "*" -- Because CPP
787+ct_wildcard = "*" <> "/" <> "*"
789getAcceptHeader :: Request -> AcceptHeader
789getAcceptHeader :: Request -> AcceptHeader
790getAcceptHeader = AcceptHeader . fromMaybe ct_wildcard . lookup hAccept . requestHeaders
790getAcceptHeader = AcceptHeader . fromMaybe ct_wildcard . lookup hAccept . requestHeaders
@@ -815,7 +815,6 @@ instance (HasContextEntry context (NamedContext name subContext), HasServer subA
815-- TypeError helpers
815-- TypeError helpers
816-------------------------------------------------------------------------------
816-------------------------------------------------------------------------------
818−#ifdef HAS_TYPE_ERROR
819-- | This instance catches mistakes when there are non-saturated
818-- | This instance catches mistakes when there are non-saturated
820-- type applications on LHS of ':>'.
819-- type applications on LHS of ':>'.
@@ -878,7 +877,6 @@ type HasServerArrowTypeError a b =
878 ':$$: 'ShowType a
877 ':$$: 'ShowType a
879 ':$$: 'Text "and"
878 ':$$: 'Text "and"
880 ':$$: 'ShowType b
879 ':$$: 'ShowType b
883-- | Ignore @'Fragment'@ in server handlers.
881-- | Ignore @'Fragment'@ in server handlers.
884-- See <https://ietf.org/rfc/rfc2616.html#section-15.1.3> for more details.
882-- See <https://ietf.org/rfc/rfc2616.html#section-15.1.3> for more details.
@@ -891,11 +889,7 @@ type HasServerArrowTypeError a b =
891-- > server = getBooks
889-- > server = getBooks
892-- > where getBooks :: Handler [Book]
890-- > where getBooks :: Handler [Book]
893-- > getBooks = ...return all books...
891-- > getBooks = ...return all books...
894−#ifdef HAS_TYPE_ERROR
895instance (AtLeastOneFragment api, FragmentUnique (Fragment a1 :> api), HasServer api context)
892instance (AtLeastOneFragment api, FragmentUnique (Fragment a1 :> api), HasServer api context)
897−instance (HasServer api context)
899 => HasServer (Fragment a1 :> api) context where
893 => HasServer (Fragment a1 :> api) context where
900 type ServerT (Fragment a1 :> api) m = ServerT api m
894 type ServerT (Fragment a1 :> api) m = ServerT api m
@@ -905,3 +899,72 @@ instance (HasServer api context)
907-- >>> import Servant
901-- >>> import Servant
903+-- | A type that specifies that an API record contains a server implementation.
904+data AsServerT (m :: * -> *)
905+instance GenericMode (AsServerT m) where
906+ type AsServerT m :- api = ServerT api m
908+type AsServer = AsServerT Handler
911+-- | Set of constraints required to convert to / from vanilla server types.
912+type GServerConstraints api m =
913+ ( ToServant api (AsServerT m) ~ ServerT (ToServantApi api) m
914+ , GServantProduct (Rep (api (AsServerT m)))
917+-- | This class is a necessary evil: in the implementation of 'HasServer' for
918+-- @'NamedRoutes' api@, we essentially need the quantified constraint @forall
919+-- m. 'GServerConstraints' m@ to hold.
921+-- We cannot require do that directly as the definition of 'GServerConstraints'
922+-- contains type family applications ('Rep' and 'ServerT'). The trick is to hide
923+-- those type family applications behind a typeclass providing evidence for
924+-- @'GServerConstraints' api m@ in the form of a dictionary, and require that
925+-- @forall m. 'GServer' api m@ instead.
927+-- Users shouldn't have to worry about this class, as the only possible instance
928+-- is provided in this module for all record APIs.
930+class GServer (api :: * -> *) (m :: * -> *) where
931+ proof :: Dict (GServerConstraints api m)
934+ ( ToServant api (AsServerT m) ~ ServerT (ToServantApi api) m
935+ , GServantProduct (Rep (api (AsServerT m)))
936+ ) => GServer api m where
940+ ( HasServer (ToServantApi api) context
941+ , forall m. Generic (api (AsServerT m))
942+ , forall m. GServer api m
943+ ) => HasServer (NamedRoutes api) context where
945+ type ServerT (NamedRoutes api) m = api (AsServerT m)
948+ :: Proxy (NamedRoutes api)
950+ -> Delayed env (api (AsServerT Handler))
952+ route _ ctx delayed =
953+ case proof @api @Handler of
954+ Dict -> route (Proxy @(ToServantApi api)) ctx (toServant <$> delayed)
956+ hoistServerWithContext
957+ :: forall m n. Proxy (NamedRoutes api)
959+ -> (forall x. m x -> n x)
960+ -> api (AsServerT m)
961+ -> api (AsServerT n)
962+ hoistServerWithContext _ pctx nat server =
963+ case (proof @api @m, proof @api @n) of
965+ fromServant servantSrvN
967+ servantSrvM :: ServerT (ToServantApi api) m =
969+ servantSrvN :: ServerT (ToServantApi api) n =
970+ hoistServerWithContext (Proxy @(ToServantApi api)) pctx nat servantSrvM