@@ -0,0 +1,576 @@
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE InstanceSigs #-}
6+{-# LANGUAGE OverloadedStrings #-}
7+{-# LANGUAGE ScopedTypeVariables #-}
8+{-# LANGUAGE TypeFamilies #-}
9+{-# LANGUAGE TypeOperators #-}
10+{-# LANGUAGE UndecidableInstances #-}
11+#if !MIN_VERSION_base(4,8,0)
12+{-# LANGUAGE OverlappingInstances #-}
14+-- | This module provides 'client' which can automatically generate
15+-- querying functions for each endpoint just from the type representing your
19+ , HasReflexClient(..)
21+ , module Servant.Common.BaseUrl
24+#if !MIN_VERSION_base(4,8,0)
25+import Control.Applicative ((<$>))
28+import Control.Monad.Trans.Except
29+import Data.ByteString.Lazy (ByteString)
32+import Data.String.Conversions
33+import Data.Text (unpack)
35+import Network.HTTP.Media
36+import qualified Network.HTTP.Types as H
37+import qualified Network.HTTP.Types.Header as HTTP
39+import Servant.Common.BaseUrl
40+import Servant.Common.Req
41+import Web.HttpApiData
43+-- * Accessing APIs as a Client
45+-- | 'client' allows you to produce operations to query an API from a client.
47+-- > type MyApi = "books" :> Get '[JSON] [Book] -- GET /books
48+-- > :<|> "books" :> ReqBody '[JSON] Book :> Post Book -- POST /books
50+-- > myApi :: Proxy MyApi
53+-- > getAllBooks :: ExceptT String IO [Book]
54+-- > postNewBook :: Book -> ExceptT String IO Book
55+-- > (getAllBooks :<|> postNewBook) = client myApi host
56+-- > where host = BaseUrl Http "localhost" 8080
57+client :: HasReflexClient layout => Proxy layout -> BaseUrl -> Input layout -> Client layout
58+client p baseurl = clientWithRoute p defReq baseurl
60+type Final a = forall m. m a
62+data a ::> b = a ::> b deriving (Eq,Ord,Show,Read)
66+-- | This class lets us define how each API combinator
67+-- influences the creation of an HTTP request. It's mostly
68+-- an internal class, you can just use 'client'.
69+class HasReflexClient layout where
70+ type Input layout :: *
71+ type Client layout :: *
72+ clientWithRoute :: Proxy layout -> Req -> BaseUrl -> Input layout -> Client layout
75+-- | If you have a 'Get' endpoint in your API, the client
76+-- side querying function that is created when calling 'client'
77+-- will just require an argument that specifies the scheme, host
78+-- and port to send the request to.
80+#if MIN_VERSION_base(4,8,0)
83+ (MimeUnrender ct result) => HasReflexClient (Get (ct ': cts) result) where
84+ type Input (Get (ct ': cts) result) = ()
85+ type Client (Get (ct ': cts) result) = Final result
86+ clientWithRoute Proxy req baseurl _ =
87+ snd <$> performRequestCT (Proxy :: Proxy ct) H.methodGet req baseurl
90+#if MIN_VERSION_base(4,8,0)
93+ HasReflexClient (Get (ct ': cts) ()) where
94+ type Input (Get (ct ': cts) ()) = ()
95+ type Client (Get (ct ': cts) ()) = Final ()
96+ clientWithRoute Proxy req baseurl _ =
97+ performRequestNoBody H.methodGet req baseurl
99+-- | Pick a 'Method' and specify where the server you want to query is. You get
100+-- back the full `Response`.
101+instance HasReflexClient Raw where
102+ type Input Raw = H.Method ::> ()
103+ type Client Raw = Final (Int, ByteString, MediaType, [HTTP.Header], Response ByteString)
105+ clientWithRoute :: Proxy Raw -> Req -> BaseUrl -> Input Raw -> Client Raw
106+ clientWithRoute Proxy req baseurl (httpMethod ::> ()) = do
107+ performRequest httpMethod req baseurl
109+-- -- | If you have a 'Get xs (Headers ls x)' endpoint, the client expects the
110+-- -- corresponding headers.
112+-- #if MIN_VERSION_base(4,8,0)
113+-- {-# OVERLAPPING #-}
115+-- ( MimeUnrender ct a, BuildHeadersTo ls
116+-- ) => HasReflexClient (Get (ct ': cts) (Headers ls a)) where
117+-- type Input (Get (ct ': cts) (Headers ls a)) = ()
118+-- type Client (Get (ct ': cts) (Headers ls a)) = Final (Headers ls a)
119+-- clientWithRoute Proxy req baseurl _ = do
120+-- (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodGet req baseurl
121+-- return $ Headers { getResponse = resp
122+-- , getHeadersHList = buildHeadersTo hdrs
125+-- -- | A client querying function for @a ':<|>' b@ will actually hand you
126+-- -- one function for querying @a@ and another one for querying @b@,
127+-- -- stitching them together with ':<|>', which really is just like a pair.
129+-- -- > type MyApi = "books" :> Get '[JSON] [Book] -- GET /books
130+-- -- > :<|> "books" :> ReqBody '[JSON] Book :> Post Book -- POST /books
132+-- -- > myApi :: Proxy MyApi
133+-- -- > myApi = Proxy
135+-- -- > getAllBooks :: ExceptT String IO [Book]
136+-- -- > postNewBook :: Book -> ExceptT String IO Book
137+-- -- > (getAllBooks :<|> postNewBook) = client myApi host
138+-- -- > where host = BaseUrl Http "localhost" 8080
139+-- instance (HasReflexClient a, HasReflexClient b) => HasReflexClient (a :<|> b) where
140+-- type Input (a :<|> b) = Input a :<|> Input b
141+-- type Client (a :<|> b) = Client a :<|> Client b
142+-- clientWithRoute Proxy req baseurl (a :<|> b) =
143+-- clientWithRoute (Proxy :: Proxy a) req baseurl a :<|>
144+-- clientWithRoute (Proxy :: Proxy b) req baseurl b
146+-- ------------------------------------------------------------------------------
147+-- -- | If you use a 'Capture' in one of your endpoints in your API,
148+-- -- the corresponding querying function will automatically take
149+-- -- an additional argument of the type specified by your 'Capture'.
150+-- -- That function will take care of inserting a textual representation
151+-- -- of this value at the right place in the request path.
153+-- -- You can control how values for this type are turned into
154+-- -- text by specifying a 'ToHttpApiData' instance for your type.
158+-- -- > type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book
160+-- -- > myApi :: Proxy MyApi
161+-- -- > myApi = Proxy
163+-- -- > getBook :: Text -> ExceptT String IO Book
164+-- -- > getBook = client myApi host
165+-- -- > where host = BaseUrl Http "localhost" 8080
166+-- -- > -- then you can just use "getBook" to query that endpoint
167+-- instance (KnownSymbol capture, ToHttpApiData a, HasReflexClient sublayout)
168+-- => HasReflexClient (Capture capture a :> sublayout) where
170+-- type Input (Capture cap a :> sublayout) = a ::> Input sublayout
171+-- type Client (Capture capture a :> sublayout) = Client sublayout
173+-- clientWithRoute Proxy req baseurl (val ::> rest) =
174+-- clientWithRoute (Proxy :: Proxy sublayout)
175+-- (appendToPath p req) baseurl rest
177+-- where p = unpack (toUrlPiece val)
179+-- -- | If you have a 'Delete' endpoint in your API, the client
180+-- -- side querying function that is created when calling 'client'
181+-- -- will just require an argument that specifies the scheme, host
182+-- -- and port to send the request to.
184+-- #if MIN_VERSION_base(4,8,0)
185+-- {-# OVERLAPPABLE #-}
187+-- (MimeUnrender ct a, cts' ~ (ct ': cts)) => HasReflexClient (Delete cts' a) where
188+-- type Input (Delete cts' a) = ()
189+-- type Client (Delete cts' a) = Final a
190+-- clientWithRoute Proxy req baseurl val =
191+-- snd <$> performRequestCT (Proxy :: Proxy ct) H.methodDelete req baseurl val
194+-- #if MIN_VERSION_base(4,8,0)
195+-- {-# OVERLAPPING #-}
197+-- HasReflexClient (Delete cts ()) where
198+-- type Input (Delete cts ()) = ()
199+-- type Client (Delete cts ()) = Final ()
200+-- clientWithRoute Proxy req baseurl val =
201+-- void $ performRequestNoBody H.methodDelete req baseurl val
203+-- -- | If you have a 'Delete xs (Headers ls x)' endpoint, the client expects the
204+-- -- corresponding headers.
206+-- #if MIN_VERSION_base(4,8,0)
207+-- {-# OVERLAPPING #-}
209+-- ( MimeUnrender ct a, BuildHeadersTo ls, cts' ~ (ct ': cts)
210+-- ) => HasReflexClient (Delete cts' (Headers ls a)) where
211+-- type Input (Delete cts' (Headers ls a)) = ()
212+-- type Client (Delete cts' (Headers ls a)) = Final (Headers ls a)
213+-- clientWithRoute Proxy req baseurl _ = do
214+-- (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodDelete req baseurl
215+-- return $ Headers { getResponse = resp
216+-- , getHeadersHList = buildHeadersTo hdrs
219+-- -- | If you use a 'Header' in one of your endpoints in your API,
220+-- -- the corresponding querying function will automatically take
221+-- -- an additional argument of the type specified by your 'Header',
222+-- -- wrapped in Maybe.
224+-- -- That function will take care of encoding this argument as Text
225+-- -- in the request headers.
227+-- -- All you need is for your type to have a 'ToHttpApiData' instance.
231+-- -- > newtype Referer = Referer { referrer :: Text }
232+-- -- > deriving (Eq, Show, Generic, FromText, ToHttpApiData)
234+-- -- > -- GET /view-my-referer
235+-- -- > type MyApi = "view-my-referer" :> Header "Referer" Referer :> Get '[JSON] Referer
237+-- -- > myApi :: Proxy MyApi
238+-- -- > myApi = Proxy
240+-- -- > viewReferer :: Maybe Referer -> ExceptT String IO Book
241+-- -- > viewReferer = client myApi host
242+-- -- > where host = BaseUrl Http "localhost" 8080
243+-- -- > -- then you can just use "viewRefer" to query that endpoint
244+-- -- > -- specifying Nothing or e.g Just "http://haskell.org/" as arguments
245+-- instance (KnownSymbol sym, ToHttpApiData a, HasReflexClient sublayout)
246+-- => HasReflexClient (Header sym a :> sublayout) where
248+-- type Input (Header sym a :> sublayout) = Maybe a ::> Input sublayout
249+-- type Client (Header sym a :> sublayout) = Client sublayout
251+-- clientWithRoute Proxy req baseurl (mval ::> rest) =
252+-- clientWithRoute (Proxy :: Proxy sublayout)
254+-- (\value -> Servant.Common.Req.addHeader hname value req)
259+-- where hname = symbolVal (Proxy :: Proxy sym)
261+-- -- | If you have a 'Post' endpoint in your API, the client
262+-- -- side querying function that is created when calling 'client'
263+-- -- will just require an argument that specifies the scheme, host
264+-- -- and port to send the request to.
266+-- #if MIN_VERSION_base(4,8,0)
267+-- {-# OVERLAPPABLE #-}
269+-- (MimeUnrender ct a) => HasReflexClient (Post (ct ': cts) a) where
270+-- type Input (Post (ct ': cts) a) = ()
271+-- type Client (Post (ct ': cts) a) = Final a
272+-- clientWithRoute Proxy req baseurl _ =
273+-- snd <$> performRequestCT (Proxy :: Proxy ct) H.methodPost req baseurl
276+-- #if MIN_VERSION_base(4,8,0)
277+-- {-# OVERLAPPING #-}
279+-- HasReflexClient (Post (ct ': cts) ()) where
280+-- type Input (Post (ct ': cts) ()) = ()
281+-- type Client (Post (ct ': cts) ()) = Final ()
282+-- clientWithRoute Proxy req baseurl _ =
283+-- void $ performRequestNoBody H.methodPost req baseurl
285+-- -- | If you have a 'Post xs (Headers ls x)' endpoint, the client expects the
286+-- -- corresponding headers.
288+-- #if MIN_VERSION_base(4,8,0)
289+-- {-# OVERLAPPING #-}
291+-- ( MimeUnrender ct a, BuildHeadersTo ls
292+-- ) => HasReflexClient (Post (ct ': cts) (Headers ls a)) where
293+-- type Input (Post (ct ': cts) (Headers ls a)) = ()
294+-- type Client (Post (ct ': cts) (Headers ls a)) = Final (Headers ls a)
295+-- clientWithRoute Proxy req baseurl _ = do
296+-- (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodPost req baseurl
297+-- return $ Headers { getResponse = resp
298+-- , getHeadersHList = buildHeadersTo hdrs
301+-- -- | If you have a 'Put' endpoint in your API, the client
302+-- -- side querying function that is created when calling 'client'
303+-- -- will just require an argument that specifies the scheme, host
304+-- -- and port to send the request to.
306+-- #if MIN_VERSION_base(4,8,0)
307+-- {-# OVERLAPPABLE #-}
309+-- (MimeUnrender ct a) => HasReflexClient (Put (ct ': cts) a) where
310+-- type Input (Put (ct ': cts) a) = ()
311+-- type Client (Put (ct ': cts) a) = Final a
312+-- clientWithRoute Proxy req baseurl _ =
313+-- snd <$> performRequestCT (Proxy :: Proxy ct) H.methodPut req baseurl
316+-- #if MIN_VERSION_base(4,8,0)
317+-- {-# OVERLAPPING #-}
319+-- HasReflexClient (Put (ct ': cts) ()) where
320+-- type Input (Put (ct ': cts) ()) = ()
321+-- type Client (Put (ct ': cts) ()) = Final ()
322+-- clientWithRoute Proxy req baseurl _ =
323+-- void $ performRequestNoBody H.methodPut req baseurl
325+-- -- | If you have a 'Put xs (Headers ls x)' endpoint, the client expects the
326+-- -- corresponding headers.
328+-- #if MIN_VERSION_base(4,8,0)
329+-- {-# OVERLAPPING #-}
331+-- ( MimeUnrender ct a, BuildHeadersTo ls
332+-- ) => HasReflexClient (Put (ct ': cts) (Headers ls a)) where
333+-- type Input (Put (ct ': cts) (Headers ls a)) = ()
334+-- type Client (Put (ct ': cts) (Headers ls a)) = Final (Headers ls a)
335+-- clientWithRoute Proxy req baseurl _ = do
336+-- (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodPut req baseurl
337+-- return $ Headers { getResponse = resp
338+-- , getHeadersHList = buildHeadersTo hdrs
341+-- -- | If you have a 'Patch' endpoint in your API, the client
342+-- -- side querying function that is created when calling 'client'
343+-- -- will just require an argument that specifies the scheme, host
344+-- -- and port to send the request to.
346+-- #if MIN_VERSION_base(4,8,0)
347+-- {-# OVERLAPPABLE #-}
349+-- (MimeUnrender ct a) => HasReflexClient (Patch (ct ': cts) a) where
350+-- type Input (Patch (ct ': cts) a) = ()
351+-- type Client (Patch (ct ': cts) a) = Final a
352+-- clientWithRoute Proxy req baseurl _ =
353+-- snd <$> performRequestCT (Proxy :: Proxy ct) H.methodPatch req baseurl
356+-- #if MIN_VERSION_base(4,8,0)
357+-- {-# OVERLAPPING #-}
359+-- HasReflexClient (Patch (ct ': cts) ()) where
360+-- type Input (Patch (ct ': cts) ()) = ()
361+-- type Client (Patch (ct ': cts) ()) = Final ()
362+-- clientWithRoute Proxy req baseurl _ =
363+-- void $ performRequestNoBody H.methodPatch req baseurl
365+-- -- | If you have a 'Patch xs (Headers ls x)' endpoint, the client expects the
366+-- -- corresponding headers.
368+-- #if MIN_VERSION_base(4,8,0)
369+-- {-# OVERLAPPING #-}
371+-- ( MimeUnrender ct a, BuildHeadersTo ls
372+-- ) => HasReflexClient (Patch (ct ': cts) (Headers ls a)) where
373+-- type Input (Patch (ct ': cts) (Headers ls a)) = ()
374+-- type Client (Patch (ct ': cts) (Headers ls a)) = Final (Headers ls a)
375+-- clientWithRoute Proxy req baseurl _ = do
376+-- (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodPatch req baseurl
377+-- return $ Headers { getResponse = resp
378+-- , getHeadersHList = buildHeadersTo hdrs
381+-- -- | If you use a 'QueryParam' in one of your endpoints in your API,
382+-- -- the corresponding querying function will automatically take
383+-- -- an additional argument of the type specified by your 'QueryParam',
384+-- -- enclosed in Maybe.
386+-- -- If you give Nothing, nothing will be added to the query string.
388+-- -- If you give a non-'Nothing' value, this function will take care
389+-- -- of inserting a textual representation of this value in the query string.
391+-- -- You can control how values for your type are turned into
392+-- -- text by specifying a 'ToHttpApiData' instance for your type.
396+-- -- > type MyApi = "books" :> QueryParam "author" Text :> Get '[JSON] [Book]
398+-- -- > myApi :: Proxy MyApi
399+-- -- > myApi = Proxy
401+-- -- > getBooksBy :: Maybe Text -> ExceptT String IO [Book]
402+-- -- > getBooksBy = client myApi host
403+-- -- > where host = BaseUrl Http "localhost" 8080
404+-- -- > -- then you can just use "getBooksBy" to query that endpoint.
405+-- -- > -- 'getBooksBy Nothing' for all books
406+-- -- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
407+-- instance (KnownSymbol sym, ToHttpApiData a, HasReflexClient sublayout)
408+-- => HasReflexClient (QueryParam sym a :> sublayout) where
410+-- type Input (QueryParam sym a :> sublayout) = Maybe a ::> Input sublayout
411+-- type Client (QueryParam sym a :> sublayout) = Client sublayout
413+-- -- if mparam = Nothing, we don't add it to the query string
414+-- clientWithRoute Proxy req baseurl (mparam ::> rest) =
415+-- clientWithRoute (Proxy :: Proxy sublayout)
417+-- (flip (appendToQueryString pname) req . Just)
422+-- where pname = cs pname'
423+-- pname' = symbolVal (Proxy :: Proxy sym)
424+-- mparamText = fmap toQueryParam mparam
426+-- -- | If you use a 'QueryParams' in one of your endpoints in your API,
427+-- -- the corresponding querying function will automatically take
428+-- -- an additional argument, a list of values of the type specified
429+-- -- by your 'QueryParams'.
431+-- -- If you give an empty list, nothing will be added to the query string.
433+-- -- Otherwise, this function will take care
434+-- -- of inserting a textual representation of your values in the query string,
435+-- -- under the same query string parameter name.
437+-- -- You can control how values for your type are turned into
438+-- -- text by specifying a 'ToHttpApiData' instance for your type.
442+-- -- > type MyApi = "books" :> QueryParams "authors" Text :> Get '[JSON] [Book]
444+-- -- > myApi :: Proxy MyApi
445+-- -- > myApi = Proxy
447+-- -- > getBooksBy :: [Text] -> ExceptT String IO [Book]
448+-- -- > getBooksBy = client myApi host
449+-- -- > where host = BaseUrl Http "localhost" 8080
450+-- -- > -- then you can just use "getBooksBy" to query that endpoint.
451+-- -- > -- 'getBooksBy []' for all books
452+-- -- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]'
453+-- -- > -- to get all books by Asimov and Heinlein
454+-- instance (KnownSymbol sym, ToHttpApiData a, HasReflexClient sublayout)
455+-- => HasReflexClient (QueryParams sym a :> sublayout) where
457+-- type Input (QueryParams sym a :> sublayout) = [a] ::> Input sublayout
458+-- type Client (QueryParams sym a :> sublayout) = Client sublayout
460+-- clientWithRoute Proxy req baseurl (paramlist ::> rest) =
461+-- clientWithRoute (Proxy :: Proxy sublayout)
462+-- (foldl' (\ req' -> maybe req' (flip (appendToQueryString pname) req' . Just))
468+-- where pname = cs pname'
469+-- pname' = symbolVal (Proxy :: Proxy sym)
470+-- paramlist' = map (Just . toQueryParam) paramlist
472+-- -- | If you use a 'QueryFlag' in one of your endpoints in your API,
473+-- -- the corresponding querying function will automatically take
474+-- -- an additional 'Bool' argument.
476+-- -- If you give 'False', nothing will be added to the query string.
478+-- -- Otherwise, this function will insert a value-less query string
479+-- -- parameter under the name associated to your 'QueryFlag'.
483+-- -- > type MyApi = "books" :> QueryFlag "published" :> Get '[JSON] [Book]
485+-- -- > myApi :: Proxy MyApi
486+-- -- > myApi = Proxy
488+-- -- > getBooks :: Bool -> ExceptT String IO [Book]
489+-- -- > getBooks = client myApi host
490+-- -- > where host = BaseUrl Http "localhost" 8080
491+-- -- > -- then you can just use "getBooks" to query that endpoint.
492+-- -- > -- 'getBooksBy False' for all books
493+-- -- > -- 'getBooksBy True' to only get _already published_ books
494+-- instance (KnownSymbol sym, HasReflexClient sublayout)
495+-- => HasReflexClient (QueryFlag sym :> sublayout) where
497+-- type Input (QueryFlag sym :> sublayout) = Bool ::> Input sublayout
498+-- type Client (QueryFlag sym :> sublayout) = Client sublayout
500+-- clientWithRoute Proxy req baseurl (flag ::> rest) =
501+-- clientWithRoute (Proxy :: Proxy sublayout)
503+-- then appendToQueryString paramname Nothing req
508+-- where paramname = cs $ symbolVal (Proxy :: Proxy sym)
511+-- -- | If you use a 'ReqBody' in one of your endpoints in your API,
512+-- -- the corresponding querying function will automatically take
513+-- -- an additional argument of the type specified by your 'ReqBody'.
514+-- -- That function will take care of encoding this argument as JSON and
515+-- -- of using it as the request body.
517+-- -- All you need is for your type to have a 'ToJSON' instance.
521+-- -- > type MyApi = "books" :> ReqBody '[JSON] Book :> Post '[JSON] Book
523+-- -- > myApi :: Proxy MyApi
524+-- -- > myApi = Proxy
526+-- -- > addBook :: Book -> ExceptT String IO Book
527+-- -- > addBook = client myApi host
528+-- -- > where host = BaseUrl Http "localhost" 8080
529+-- -- > -- then you can just use "addBook" to query that endpoint
530+-- instance (MimeRender ct a, HasReflexClient sublayout)
531+-- => HasReflexClient (ReqBody (ct ': cts) a :> sublayout) where
533+-- type Input (ReqBody (ct ': cts) a :> sublayout) = a ::> Input sublayout
534+-- type Client (ReqBody (ct ': cts) a :> sublayout) = Client sublayout
536+-- clientWithRoute Proxy req baseurl (body ::> rest) =
537+-- clientWithRoute (Proxy :: Proxy sublayout)
538+-- (let ctProxy = Proxy :: Proxy ct
539+-- in setRQBody (mimeRender ctProxy body)
540+-- (contentType ctProxy)
545+-- -- | Make the querying function append @path@ to the request path.
546+-- instance (KnownSymbol path, HasReflexClient sublayout) => HasReflexClient (path :> sublayout) where
547+-- type Input (path :> sublayout) = Input sublayout
548+-- type Client (path :> sublayout) = Client sublayout
550+-- clientWithRoute Proxy req baseurl val =
551+-- clientWithRoute (Proxy :: Proxy sublayout)
552+-- (appendToPath p req)
555+-- where p = symbolVal (Proxy :: Proxy path)
557+-- instance HasReflexClient api => HasReflexClient (Vault :> api) where
558+-- type Input (Vault :> api) = Input api
559+-- type Client (Vault :> api) = Client api
561+-- clientWithRoute Proxy req baseurl val =
562+-- clientWithRoute (Proxy :: Proxy api) req baseurl val
564+-- instance HasReflexClient api => HasReflexClient (RemoteHost :> api) where
565+-- type Input (RemoteHost :> api) = Input api
566+-- type Client (RemoteHost :> api) = Client api
568+-- clientWithRoute Proxy req baseurl val =
569+-- clientWithRoute (Proxy :: Proxy api) req baseurl val
571+-- instance HasReflexClient api => HasReflexClient (IsSecure :> api) where
572+-- type Input (IsSecure :> api) = Input api
573+-- type Client (IsSecure :> api) = Client api
575+-- clientWithRoute Proxy req baseurl val =
576+-- clientWithRoute (Proxy :: Proxy api) req baseurl val