@@ -8,6 +8,7 @@
8{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE MultiParamTypeClasses #-}
9{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE OverloadedStrings #-}
10{-# LANGUAGE PolyKinds #-}
10{-# LANGUAGE PolyKinds #-}
11+{-# LANGUAGE RankNTypes #-}
11{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE TypeFamilies #-}
13{-# LANGUAGE TypeFamilies #-}
13{-# LANGUAGE TypeOperators #-}
14{-# LANGUAGE TypeOperators #-}
@@ -33,7 +34,7 @@ import Data.Maybe (fromMaybe, mapMaybe)
33import Data.Either (partitionEithers)
34import Data.Either (partitionEithers)
34import Data.String (fromString)
35import Data.String (fromString)
35import Data.String.Conversions (cs, (<>))
36import Data.String.Conversions (cs, (<>))
36−import Data.Tagged (Tagged(..), untag)
37+import Data.Tagged (Tagged(..), retag, untag)
37import qualified Data.Text as T
38import qualified Data.Text as T
38import Data.Typeable
39import Data.Typeable
39import GHC.TypeLits (KnownNat, KnownSymbol, natVal,
40import GHC.TypeLits (KnownNat, KnownSymbol, natVal,
@@ -85,6 +86,13 @@ class HasServer api context where
85 -> Delayed env (Server api)
86 -> Delayed env (Server api)
86 -> Router env
87 -> Router env
92+ -> (forall x. m x -> n x)
88type Server api = ServerT api Handler
96type Server api = ServerT api Handler
90-- * Instances
98-- * Instances
@@ -109,6 +117,11 @@ instance (HasServer a context, HasServer b context) => HasServer (a :<|> b) cont
109 where pa = Proxy :: Proxy a
117 where pa = Proxy :: Proxy a
110 pb = Proxy :: Proxy b
118 pb = Proxy :: Proxy b
120+ -- | This is better than 'enter', as it's taylor made for 'HasServer'.
121+ hoistServer _ pc nt (a :<|> b) =
122+ hoistServer (Proxy :: Proxy a) pc nt a :<|>
123+ hoistServer (Proxy :: Proxy b) pc nt b
112-- | If you use 'Capture' in one of the endpoints for your API,
125-- | If you use 'Capture' in one of the endpoints for your API,
113-- this automatically requires your server-side handler to be a function
126-- this automatically requires your server-side handler to be a function
114-- that takes an argument of the type specified by the 'Capture'.
127-- that takes an argument of the type specified by the 'Capture'.
@@ -132,6 +145,8 @@ instance (KnownSymbol capture, FromHttpApiData a, HasServer api context)
132 type ServerT (Capture capture a :> api) m =
145 type ServerT (Capture capture a :> api) m =
133 a -> ServerT api m
146 a -> ServerT api m
148+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
135 route Proxy context d =
150 route Proxy context d =
136 CaptureRouter $
151 CaptureRouter $
137 route (Proxy :: Proxy api)
152 route (Proxy :: Proxy api)
@@ -158,15 +173,17 @@ instance (KnownSymbol capture, FromHttpApiData a, HasServer api context)
158-- > server = getSourceFile
173-- > server = getSourceFile
159-- > where getSourceFile :: [Text] -> Handler Book
174-- > where getSourceFile :: [Text] -> Handler Book
160-- > getSourceFile pathSegments = ...
175-- > getSourceFile pathSegments = ...
161−instance (KnownSymbol capture, FromHttpApiData a, HasServer sublayout context)
176+instance (KnownSymbol capture, FromHttpApiData a, HasServer api context)
162− => HasServer (CaptureAll capture a :> sublayout) context where
177+ => HasServer (CaptureAll capture a :> api) context where
164− type ServerT (CaptureAll capture a :> sublayout) m =
179+ type ServerT (CaptureAll capture a :> api) m =
165− [a] -> ServerT sublayout m
180+ [a] -> ServerT api m
182+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
167 route Proxy context d =
184 route Proxy context d =
168 CaptureAllRouter $
185 CaptureAllRouter $
169− route (Proxy :: Proxy sublayout)
186+ route (Proxy :: Proxy api)
171 (addCapture d $ \ txts -> case parseUrlPieces txts of
188 (addCapture d $ \ txts -> case parseUrlPieces txts of
172 Left _ -> delayedFail err400
189 Left _ -> delayedFail err400
@@ -241,6 +258,7 @@ instance OVERLAPPABLE_
241 ) => HasServer (Verb method status ctypes a) context where
258 ) => HasServer (Verb method status ctypes a) context where
243 type ServerT (Verb method status ctypes a) m = m a
260 type ServerT (Verb method status ctypes a) m = m a
261+ hoistServer _ _ nt s = nt s
245 route Proxy _ = methodRouter method (Proxy :: Proxy ctypes) status
263 route Proxy _ = methodRouter method (Proxy :: Proxy ctypes) status
246 where method = reflectMethod (Proxy :: Proxy method)
264 where method = reflectMethod (Proxy :: Proxy method)
@@ -252,6 +270,7 @@ instance OVERLAPPING_
252 ) => HasServer (Verb method status ctypes (Headers h a)) context where
270 ) => HasServer (Verb method status ctypes (Headers h a)) context where
254 type ServerT (Verb method status ctypes (Headers h a)) m = m (Headers h a)
272 type ServerT (Verb method status ctypes (Headers h a)) m = m (Headers h a)
273+ hoistServer _ _ nt s = nt s
256 route Proxy _ = methodRouterHeaders method (Proxy :: Proxy ctypes) status
275 route Proxy _ = methodRouterHeaders method (Proxy :: Proxy ctypes) status
257 where method = reflectMethod (Proxy :: Proxy method)
276 where method = reflectMethod (Proxy :: Proxy method)
@@ -283,6 +302,8 @@ instance (KnownSymbol sym, FromHttpApiData a, HasServer api context)
283 type ServerT (Header sym a :> api) m =
302 type ServerT (Header sym a :> api) m =
284 Maybe a -> ServerT api m
303 Maybe a -> ServerT api m
305+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
286 route Proxy context subserver = route (Proxy :: Proxy api) context $
307 route Proxy context subserver = route (Proxy :: Proxy api) context $
287 subserver `addHeaderCheck` withRequest headerCheck
308 subserver `addHeaderCheck` withRequest headerCheck
@@ -326,6 +347,8 @@ instance (KnownSymbol sym, FromHttpApiData a, HasServer api context)
326 type ServerT (QueryParam sym a :> api) m =
347 type ServerT (QueryParam sym a :> api) m =
327 Maybe a -> ServerT api m
348 Maybe a -> ServerT api m
350+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
329 route Proxy context subserver =
352 route Proxy context subserver =
330 let querytext req = parseQueryText $ rawQueryString req
353 let querytext req = parseQueryText $ rawQueryString req
331 parseParam req =
354 parseParam req =
@@ -371,6 +394,8 @@ instance (KnownSymbol sym, FromHttpApiData a, HasServer api context)
371 type ServerT (QueryParams sym a :> api) m =
394 type ServerT (QueryParams sym a :> api) m =
372 [a] -> ServerT api m
395 [a] -> ServerT api m
397+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
374 route Proxy context subserver = route (Proxy :: Proxy api) context $
399 route Proxy context subserver = route (Proxy :: Proxy api) context $
375 subserver `addParameterCheck` withRequest paramsCheck
400 subserver `addParameterCheck` withRequest paramsCheck
@@ -411,6 +436,8 @@ instance (KnownSymbol sym, HasServer api context)
411 type ServerT (QueryFlag sym :> api) m =
436 type ServerT (QueryFlag sym :> api) m =
412 Bool -> ServerT api m
437 Bool -> ServerT api m
439+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
414 route Proxy context subserver =
441 route Proxy context subserver =
415 let querytext r = parseQueryText $ rawQueryString r
442 let querytext r = parseQueryText $ rawQueryString r
416 param r = case lookup paramname (querytext r) of
443 param r = case lookup paramname (querytext r) of
@@ -434,6 +461,8 @@ instance HasServer Raw context where
435 type ServerT Raw m = Tagged m Application
462 type ServerT Raw m = Tagged m Application
464+ hoistServer _ _ _ = retag
437 route Proxy _ rawApplication = RawRouter $ \ env request respond -> runResourceT $ do
466 route Proxy _ rawApplication = RawRouter $ \ env request respond -> runResourceT $ do
438 -- note: a Raw application doesn't register any cleanup
467 -- note: a Raw application doesn't register any cleanup
439 -- but for the sake of consistency, we nonetheless run
468 -- but for the sake of consistency, we nonetheless run
@@ -473,6 +502,8 @@ instance ( AllCTUnrender list a, HasServer api context
473 type ServerT (ReqBody list a :> api) m =
502 type ServerT (ReqBody list a :> api) m =
474 a -> ServerT api m
503 a -> ServerT api m
505+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
476 route Proxy context subserver
507 route Proxy context subserver
477 = route (Proxy :: Proxy api) context $
508 = route (Proxy :: Proxy api) context $
478 addBodyCheck subserver ctCheck bodyCheck
509 addBodyCheck subserver ctCheck bodyCheck
@@ -507,44 +538,51 @@ instance (KnownSymbol path, HasServer api context) => HasServer (path :> api) co
507 (cs (symbolVal proxyPath))
538 (cs (symbolVal proxyPath))
508 (route (Proxy :: Proxy api) context subserver)
539 (route (Proxy :: Proxy api) context subserver)
509 where proxyPath = Proxy :: Proxy path
540 where proxyPath = Proxy :: Proxy path
541+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt s
511instance HasServer api context => HasServer (RemoteHost :> api) context where
543instance HasServer api context => HasServer (RemoteHost :> api) context where
512 type ServerT (RemoteHost :> api) m = SockAddr -> ServerT api m
544 type ServerT (RemoteHost :> api) m = SockAddr -> ServerT api m
514 route Proxy context subserver =
546 route Proxy context subserver =
515 route (Proxy :: Proxy api) context (passToServer subserver remoteHost)
547 route (Proxy :: Proxy api) context (passToServer subserver remoteHost)
548+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
517instance HasServer api context => HasServer (IsSecure :> api) context where
550instance HasServer api context => HasServer (IsSecure :> api) context where
518 type ServerT (IsSecure :> api) m = IsSecure -> ServerT api m
551 type ServerT (IsSecure :> api) m = IsSecure -> ServerT api m
520 route Proxy context subserver =
553 route Proxy context subserver =
521 route (Proxy :: Proxy api) context (passToServer subserver secure)
554 route (Proxy :: Proxy api) context (passToServer subserver secure)
523 where secure req = if isSecure req then Secure else NotSecure
555 where secure req = if isSecure req then Secure else NotSecure
557+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
525instance HasServer api context => HasServer (Vault :> api) context where
559instance HasServer api context => HasServer (Vault :> api) context where
526 type ServerT (Vault :> api) m = Vault -> ServerT api m
560 type ServerT (Vault :> api) m = Vault -> ServerT api m
528 route Proxy context subserver =
562 route Proxy context subserver =
529 route (Proxy :: Proxy api) context (passToServer subserver vault)
563 route (Proxy :: Proxy api) context (passToServer subserver vault)
564+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
531instance HasServer api context => HasServer (HttpVersion :> api) context where
566instance HasServer api context => HasServer (HttpVersion :> api) context where
532 type ServerT (HttpVersion :> api) m = HttpVersion -> ServerT api m
567 type ServerT (HttpVersion :> api) m = HttpVersion -> ServerT api m
534 route Proxy context subserver =
569 route Proxy context subserver =
535 route (Proxy :: Proxy api) context (passToServer subserver httpVersion)
570 route (Proxy :: Proxy api) context (passToServer subserver httpVersion)
571+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
537-- | Ignore @'Summary'@ in server handlers.
573-- | Ignore @'Summary'@ in server handlers.
538instance HasServer api ctx => HasServer (Summary desc :> api) ctx where
574instance HasServer api ctx => HasServer (Summary desc :> api) ctx where
539 type ServerT (Summary desc :> api) m = ServerT api m
575 type ServerT (Summary desc :> api) m = ServerT api m
541 route _ = route (Proxy :: Proxy api)
577 route _ = route (Proxy :: Proxy api)
578+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt s
543-- | Ignore @'Description'@ in server handlers.
580-- | Ignore @'Description'@ in server handlers.
544instance HasServer api ctx => HasServer (Description desc :> api) ctx where
581instance HasServer api ctx => HasServer (Description desc :> api) ctx where
545 type ServerT (Description desc :> api) m = ServerT api m
582 type ServerT (Description desc :> api) m = ServerT api m
547 route _ = route (Proxy :: Proxy api)
584 route _ = route (Proxy :: Proxy api)
585+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt s
549-- | Singleton type representing a server that serves an empty API.
587-- | Singleton type representing a server that serves an empty API.
550data EmptyServer = EmptyServer deriving (Typeable, Eq, Show, Bounded, Enum)
588data EmptyServer = EmptyServer deriving (Typeable, Eq, Show, Bounded, Enum)
@@ -564,6 +602,8 @@ instance HasServer EmptyAPI context where
565 route Proxy _ _ = StaticRouter mempty mempty
603 route Proxy _ _ = StaticRouter mempty mempty
605+ hoistServer _ _ _ = retag
567-- | Basic Authentication
607-- | Basic Authentication
568instance ( KnownSymbol realm
608instance ( KnownSymbol realm
569 , HasServer api context
609 , HasServer api context
@@ -580,6 +620,8 @@ instance ( KnownSymbol realm
580 basicAuthContext = getContextEntry context
620 basicAuthContext = getContextEntry context
581 authCheck = withRequest $ \ req -> runBasicAuth req realm basicAuthContext
621 authCheck = withRequest $ \ req -> runBasicAuth req realm basicAuthContext
623+ hoistServer _ pc nt s = hoistServer (Proxy :: Proxy api) pc nt . s
583-- * helpers
625-- * helpers
585ct_wildcard :: B.ByteString
627ct_wildcard :: B.ByteString
@@ -604,3 +646,5 @@ instance (HasContextEntry context (NamedContext name subContext), HasServer subA
605 subContext :: Context subContext
647 subContext :: Context subContext
606 subContext = descendIntoNamedContext (Proxy :: Proxy name) context
648 subContext = descendIntoNamedContext (Proxy :: Proxy name) context
650+ hoistServer _ _ nt s = hoistServer (Proxy :: Proxy subApi) (Proxy :: Proxy subContext) nt s