@@ -6,10 +6,8 @@
6{-# LANGUAGE GADTs #-}
6{-# LANGUAGE GADTs #-}
7{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE LambdaCase #-}
8{-# LANGUAGE PolyKinds #-}
8{-# LANGUAGE PolyKinds #-}
9−{-# LANGUAGE RankNTypes #-}
9+
10−{-# LANGUAGE RecordWildCards #-}
11{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE ScopedTypeVariables #-}
12−{-# LANGUAGE TupleSections #-}
13{-# LANGUAGE TypeApplications #-}
11{-# LANGUAGE TypeApplications #-}
14{-# LANGUAGE TypeFamilies #-}
12{-# LANGUAGE TypeFamilies #-}
15{-# LANGUAGE UndecidableInstances #-}
13{-# LANGUAGE UndecidableInstances #-}
@@ -17,47 +15,34 @@
17{-# LANGUAGE DataKinds #-}
15{-# LANGUAGE DataKinds #-}
18{-# LANGUAGE TypeOperators #-}
16{-# LANGUAGE TypeOperators #-}
19{-# LANGUAGE FlexibleInstances #-}
17{-# LANGUAGE FlexibleInstances #-}
18+{-# LANGUAGE MultiParamTypeClasses #-}
20−module Roboservant.Types.ReifiedApi.Server where
19+module Roboservant.Types.ReifiedApi.Server(module Roboservant.Types.ReifiedApi.Server) where
22import Servant
21import Servant
23−import Servant.API.Modifiers(FoldRequired,FoldLenient)
25import Control.Monad.Except (runExceptT)
23import Control.Monad.Except (runExceptT)
26import Data.Bifunctor
24import Data.Bifunctor
27import Data.Dynamic (Dynamic)
25import Data.Dynamic (Dynamic)
29import Data.List.NonEmpty (NonEmpty)
26import Data.List.NonEmpty (NonEmpty)
30import Data.Typeable (Typeable)
27import Data.Typeable (Typeable)
31−import GHC.TypeLits (Symbol)
32import Roboservant.Types.Breakdown
28import Roboservant.Types.Breakdown
33−import Roboservant.Types.BuildFrom
34−import Roboservant.Types.FlattenServer
35import Roboservant.Types.ReifiedApi
29import Roboservant.Types.ReifiedApi
37import qualified Data.Text as T
31import qualified Data.Text as T
38−import qualified Data.Vinyl as V
39import qualified Data.Vinyl.Curry as V
32import qualified Data.Vinyl.Curry as V
40import Data.Hashable(Hashable)
33import Data.Hashable(Hashable)
35+type ReifiedApi = [(ApiOffset, ReifiedEndpoint )]
43−class ToReifiedApi (endpoints ) where
44− toReifiedApi :: Bundled endpoints -> Proxy endpoints -> ReifiedApi
46−class ( V.RecordToList (EndpointArgs endpoint)
47− , V.RMap (EndpointArgs endpoint)
48− ) => ToReifiedEndpoint (endpoint :: *) where
49− type EndpointArgs endpoint :: [Type]
50− type EndpointRes endpoint :: Type
52− reifiedEndpointArguments :: V.Rec (TypedF Argument) (EndpointArgs endpoint)
38+class ToReifiedApi endpoints where
39+ toReifiedApi :: Bundled endpoints -> Proxy endpoints -> ReifiedApi
54instance ToReifiedApi '[] where
41instance ToReifiedApi '[] where
55 toReifiedApi NoEndpoints _ = []
42 toReifiedApi NoEndpoints _ = []
58− ( Typeable (EndpointRes endpoint)
60− , NormalizeFunction (ServerT endpoint Handler)
45+ ( NormalizeFunction (ServerT endpoint Handler)
61 , Normal (ServerT endpoint Handler) ~ V.Curried (EndpointArgs endpoint) (IO (Either InteractionError (NonEmpty (Dynamic,Int))))
46 , Normal (ServerT endpoint Handler) ~ V.Curried (EndpointArgs endpoint) (IO (Either InteractionError (NonEmpty (Dynamic,Int))))
62 , ToReifiedEndpoint endpoint
47 , ToReifiedEndpoint endpoint
63 , ToReifiedApi endpoints
48 , ToReifiedApi endpoints
@@ -73,13 +58,6 @@ instance
73 : (map . first) (+1)
58 : (map . first) (+1)
74 (toReifiedApi endpoints (Proxy @endpoints))
59 (toReifiedApi endpoints (Proxy @endpoints))
76−class NormalizeFunction m where
78− normalize :: m -> Normal m
80−instance NormalizeFunction x => NormalizeFunction (r -> x) where
81− type Normal (r -> x) = r -> Normal x
82− normalize = fmap normalize
84instance (Typeable x, Hashable x, Breakdown x) => NormalizeFunction (Handler x) where
62instance (Typeable x, Hashable x, Breakdown x) => NormalizeFunction (Handler x) where
85 type Normal (Handler x) = IO (Either InteractionError (NonEmpty (Dynamic,Int)))
63 type Normal (Handler x) = IO (Either InteractionError (NonEmpty (Dynamic,Int)))
@@ -88,117 +66,49 @@ instance (Typeable x, Hashable x, Breakdown x) => NormalizeFunction (Handler x)
89 -- | TODO improve this
67 -- | TODO improve this
90 renderServerError :: ServerError -> InteractionError
68 renderServerError :: ServerError -> InteractionError
91− renderServerError = InteractionError . T.pack . show
69+ renderServerError s = InteractionError (T.pack $ show s) (errHTTPCode serverError == 500)
92− Right x -> pure $ Right $ breakdown x
95− (Typeable responseType, Breakdown responseType) =>
96− ToReifiedEndpoint (Verb method statusCode contentTypes responseType)
98− type EndpointArgs (Verb method statusCode contentTypes responseType) = '[]
99− type EndpointRes (Verb method statusCode contentTypes responseType) = responseType
100− reifiedEndpointArguments = V.RNil
102−instance
71+ Right x -> pure $ Right $ breakdown x
103− (ToReifiedEndpoint endpoint) =>
104− ToReifiedEndpoint ((x :: Symbol) :> endpoint)
106− type EndpointArgs ((x :: Symbol) :> endpoint) = EndpointArgs endpoint
107− type EndpointRes ((x :: Symbol) :> endpoint) = EndpointRes endpoint
108− reifiedEndpointArguments = reifiedEndpointArguments @endpoint
111− (ToReifiedEndpoint endpoint) =>
112− ToReifiedEndpoint (Description s :> endpoint)
114− type EndpointArgs (Description s :> endpoint) = EndpointArgs endpoint
115− type EndpointRes (Description s :> endpoint) = EndpointRes endpoint
116− reifiedEndpointArguments = reifiedEndpointArguments @endpoint
118−instance
74+-- case errHTTPCode serverError of
119− (ToReifiedEndpoint endpoint) =>
75+-- 500 -> throw serverError
120− ToReifiedEndpoint (Summary s :> endpoint)
76+-- _ ->
121− where
77+-- liftIO . logInfo . show $ ("ignoring non-500 error", serverError)
122− type EndpointArgs (Summary s :> endpoint) = EndpointArgs endpoint
123− type EndpointRes (Summary s :> endpoint) = EndpointRes endpoint
124− reifiedEndpointArguments = reifiedEndpointArguments @endpoint
127− (Typeable requestType
128− ,BuildFrom requestType
129− ,ToReifiedEndpoint endpoint) =>
130− ToReifiedEndpoint (QueryFlag name :> endpoint)
132− type EndpointArgs (QueryFlag name :> endpoint) = Bool ': EndpointArgs endpoint
133− type EndpointRes (QueryFlag name :> endpoint) = EndpointRes endpoint
134− reifiedEndpointArguments = tagType (Argument (buildFrom @Bool)) V.:& reifiedEndpointArguments @endpoint
136−type IfLenient s mods t = If (FoldLenient mods) (Either s t) t
80+data Bundled endpoints where
137−type IfRequired mods t = If (FoldRequired mods) t (Maybe t)
81+ -- AnEndpoint :: Server endpoint -> Bundled endpoints -> Bundled (endpoint ': endpoints)
138−type IfRequiredLenient s mods t = IfRequired mods (IfLenient s mods t)
82+ AnEndpoint :: Server endpoint -> Bundled endpoints -> Bundled (endpoint ': endpoints)
83+ NoEndpoints :: Bundled '[]
140−instance
85+class FlattenServer api where
141− ( BuildFrom (IfRequiredLenient T.Text mods paramType)
86+ flattenServer :: Server api -> Bundled (Endpoints api)
142− , ToReifiedEndpoint endpoint
144− ToReifiedEndpoint (QueryParam' mods name paramType :> endpoint)
146− type EndpointArgs (QueryParam' mods name paramType :> endpoint) = IfRequiredLenient T.Text mods paramType ': EndpointArgs endpoint
147− type EndpointRes (QueryParam' mods name paramType :> endpoint) = EndpointRes endpoint
148− reifiedEndpointArguments =
149− tagType (Argument (buildFrom @(IfRequiredLenient T.Text mods paramType)))
150− V.:& reifiedEndpointArguments @endpoint
153− ( BuildFrom (IfRequiredLenient T.Text mods headerType)
89+ ( FlattenServer api,
154− , ToReifiedEndpoint endpoint
90+ Endpoints endpoint ~ '[endpoint]
156− ToReifiedEndpoint (Header' mods headerName headerType :> endpoint)
92+ FlattenServer (endpoint :<|> api)
158− type EndpointArgs (Header' mods headerName headerType :> endpoint) = IfRequiredLenient T.Text mods headerType ': EndpointArgs endpoint
94+ flattenServer (endpoint :<|> server) = endpoint `AnEndpoint` flattenServer @api server
159− type EndpointRes (Header' mods headerName headerType :> endpoint) = EndpointRes endpoint
160− reifiedEndpointArguments =
161− tagType (Argument (buildFrom @(IfRequiredLenient T.Text mods headerType)))
162− V.:& reifiedEndpointArguments @endpoint
164−#if MIN_VERSION_servant(0,17,0)
166− ( BuildFrom (IfLenient String mods captureType)
167− , ToReifiedEndpoint endpoint) =>
168− ToReifiedEndpoint (Capture' mods name captureType :> endpoint)
170− type EndpointArgs (Capture' mods name captureType :> endpoint) = IfLenient String mods captureType ': EndpointArgs endpoint
171− type EndpointRes (Capture' mods name captureType :> endpoint) = EndpointRes endpoint
172− reifiedEndpointArguments =
173− tagType (Argument (buildFrom @(IfLenient String mods captureType)))
174− V.:& reifiedEndpointArguments @endpoint
177− ( BuildFrom captureType
97+ (
178− , ToReifiedEndpoint endpoint) =>
98+ Endpoints api ~ '[api]
179− ToReifiedEndpoint (Capture' mods name captureType :> endpoint)
99+ ) =>
100+ FlattenServer (x :> api)
181− type EndpointArgs (Capture' mods name captureType :> endpoint) = captureType ': EndpointArgs endpoint
102+ flattenServer server = server `AnEndpoint` NoEndpoints
182− type EndpointRes (Capture' mods name captureType :> endpoint) = EndpointRes endpoint
183− reifiedEndpointArguments =
184− tagType (Argument (buildFrom @(captureType)))
185− V.:& reifiedEndpointArguments @endpoint
187−#endif
104+instance FlattenServer (Verb method statusCode contentTypes responseType)
190− ( BuildFrom (IfLenient String mods requestType)
191− , ToReifiedEndpoint endpoint) =>
192− ToReifiedEndpoint (ReqBody' mods contentTypes requestType :> endpoint)
194− type EndpointArgs (ReqBody' mods contentTypes requestType :> endpoint) = IfLenient String mods requestType ': EndpointArgs endpoint
106+ flattenServer server = server `AnEndpoint` NoEndpoints
195− type EndpointRes (ReqBody' mods contentTypes requestType :> endpoint) = EndpointRes endpoint
196− reifiedEndpointArguments =
197− tagType (Argument (buildFrom @(IfLenient String mods requestType)))
198− V.:& reifiedEndpointArguments @endpoint
108+class NormalizeFunction m where
110+ normalize :: m -> Normal m
201−-- case errHTTPCode serverError of
112+instance NormalizeFunction x => NormalizeFunction (r -> x) where
202−-- 500 -> throw serverError
113+ type Normal (r -> x) = r -> Normal x
203−-- _ ->
114+ normalize = fmap normalize
204−-- liftIO . logInfo . show $ ("ignoring non-500 error", serverError)