@@ -12,7 +12,7 @@ module Servant.Client.Generic
1212 , genericMkClientP
1313 ) where
1414
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)
1616import Servant.API ((:<|>)(..))
1717import Servant.Client (ClientM)
1818
@@ -38,7 +38,7 @@ import Servant.Client (ClientM)
3838-- > , mkNestedClient :: Int -> NestedClient
3939-- > } deriving GHC.Generic
4040-- >
41−-- > instance Generic.SOP.Generic APIClient
41+-- > instance Generics.SOP.Generic APIClient
4242-- > instance (Client API ~ client) => ClientLike client APIClient
4343-- >
4444-- > data NestedClient = NestedClient
@@ -46,11 +46,57 @@ import Servant.Client (ClientM)
4646-- > , postBaz :: Maybe Char -> ClientM ()
4747-- > } deriving GHC.Generic
4848-- >
49−-- > instance Generic.SOP.Generic NestedClient
49+-- > instance Generics.SOP.Generic NestedClient
5050-- > instance (Client NestedAPI ~ client) => ClientLike client NestedClient
5151-- >
5252-- > mkAPIClient :: APIClient
5353-- > 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))
54100class ClientLike client custom where
55101 mkClient :: client -> custom
56102 default mkClient :: (Generic custom, Code custom ~ '[xs], GClientList client '[], GClientLikeL (ClientList client '[]) xs)
@@ -100,11 +146,12 @@ instance {-# OVERLAPPABLE #-} (ClientList client acc ~ (client ': acc))
100146 => GClientList client acc where
101147 gClientList c acc = I c :* acc
102148
103−-- | Generate client structure from client type.
149+-- | Generate client structure from client type, expanding left-nested API (done by default).
104150genericMkClientL :: (Generic custom, Code custom ~ '[xs], GClientList client '[], GClientLikeL (ClientList client '[]) xs)
105151 => client -> custom
106152genericMkClientL = to . SOP . Z . gMkClientL . flip gClientList Nil
107153
154+-- | Generate client structure from client type, regarding left-nested API clients as separate data structures.
108155genericMkClientP :: (Generic custom, Code custom ~ '[xs], GClientLikeP client xs)
109156 => client -> custom
110157genericMkClientP = to . SOP . Z . gMkClientP