@@ -12,7 +12,7 @@ module Servant.Client.Generic
12
12
, genericMkClientP
13
13
) where
14
14
15
- import Generics.SOP (Code , Generic , I (.. ), NP (.. ), NS (Z ), Rep , SOP (.. ), to )
15
+ import Generics.SOP (Code , Generic , I (.. ), NP (.. ), NS (Z ), SOP (.. ), to )
16
16
import Servant.API ((:<|>) (.. ))
17
17
import Servant.Client (ClientM )
18
18
@@ -38,19 +38,65 @@ import Servant.Client (ClientM)
38
38
-- > , mkNestedClient :: Int -> NestedClient
39
39
-- > } deriving GHC.Generic
40
40
-- >
41
- -- > instance Generic .SOP.Generic APIClient
41
+ -- > instance Generics .SOP.Generic APIClient
42
42
-- > instance (Client API ~ client) => ClientLike client APIClient
43
43
-- >
44
44
-- > data NestedClient = NestedClient
45
45
-- > { getString :: ClientM String
46
46
-- > , postBaz :: Maybe Char -> ClientM ()
47
47
-- > } deriving GHC.Generic
48
48
-- >
49
- -- > instance Generic .SOP.Generic NestedClient
49
+ -- > instance Generics .SOP.Generic NestedClient
50
50
-- > instance (Client NestedAPI ~ client) => ClientLike client NestedClient
51
51
-- >
52
52
-- > mkAPIClient :: APIClient
53
53
-- > mkAPIClient = mkClient (client (Proxy :: Proxy API))
54
+ --
55
+ -- By default, left-nested alternatives are expanded:
56
+ --
57
+ -- > type API1
58
+ -- > = "foo" :> Capture "x" Int :> Get '[JSON] Int
59
+ -- > :<|> "bar" :> QueryParam "a" Char :> Post '[JSON] String
60
+ -- >
61
+ -- > type API2
62
+ -- > = "baz" :> QueryParam "c" Char :> Post '[JSON] ()
63
+ -- >
64
+ -- > type API = API1 :<|> API2
65
+ -- >
66
+ -- > data APIClient = APIClient
67
+ -- > { getFoo :: Int -> ClientM Int
68
+ -- > , postBar :: Maybe Char -> ClientM String
69
+ -- > , postBaz :: Maybe Char -> ClientM ()
70
+ -- > } deriving GHC.Generic
71
+ -- >
72
+ -- > instance Generics.SOP.Generic APIClient
73
+ -- > instance (Client API ~ client) => ClientLike client APIClient
74
+ -- >
75
+ -- > mkAPIClient :: APIClient
76
+ -- > mkAPIClient = mkClient (client (Proxy :: Proxy API))
77
+ --
78
+ -- If you want to define client for @API1@ as a separate data structure,
79
+ -- you can use 'genericMkClientP':
80
+ --
81
+ -- > data APIClient1 = APIClient1
82
+ -- > { getFoo :: Int -> ClientM Int
83
+ -- > , postBar :: Maybe Char -> ClientM String
84
+ -- > } deriving GHC.Generic
85
+ -- >
86
+ -- > instance Generics.SOP.Generic APIClient1
87
+ -- > instance (Client API1 ~ client) => ClientLike client APIClient1
88
+ -- >
89
+ -- > data APIClient = APIClient
90
+ -- > { mkAPIClient1 :: APIClient1
91
+ -- > , postBaz :: Maybe Char -> ClientM ()
92
+ -- > } deriving GHC.Generic
93
+ -- >
94
+ -- > instance Generics.SOP.Generic APIClient
95
+ -- > instance (Client API ~ client) => ClientLike client APIClient where
96
+ -- > mkClient = genericMkClientP
97
+ -- >
98
+ -- > mkAPIClient :: APIClient
99
+ -- > mkAPIClient = mkClient (client (Proxy :: Proxy API))
54
100
class ClientLike client custom where
55
101
mkClient :: client -> custom
56
102
default mkClient :: (Generic custom , Code custom ~ '[xs ], GClientList client '[] , GClientLikeL (ClientList client '[] ) xs )
@@ -100,11 +146,12 @@ instance {-# OVERLAPPABLE #-} (ClientList client acc ~ (client ': acc))
100
146
=> GClientList client acc where
101
147
gClientList c acc = I c :* acc
102
148
103
- -- | Generate client structure from client type.
149
+ -- | Generate client structure from client type, expanding left-nested API (done by default) .
104
150
genericMkClientL :: (Generic custom , Code custom ~ '[xs ], GClientList client '[] , GClientLikeL (ClientList client '[] ) xs )
105
151
=> client -> custom
106
152
genericMkClientL = to . SOP . Z . gMkClientL . flip gClientList Nil
107
153
154
+ -- | Generate client structure from client type, regarding left-nested API clients as separate data structures.
108
155
genericMkClientP :: (Generic custom , Code custom ~ '[xs ], GClientLikeP client xs )
109
156
=> client -> custom
110
157
genericMkClientP = to . SOP . Z . gMkClientP
0 commit comments