@@ -27,15 +27,6 @@ newtype FunctionName = FunctionName { unFunctionName :: [Text] }
2727
2828makePrisms ''FunctionName
2929
30−newtype ForeignType f = ForeignType { unForeignType :: f }
31−
32−deriving instance Show f => Show (ForeignType f)
33−deriving instance Eq f => Eq (ForeignType f)
34−deriving instance IsString f => IsString (ForeignType f)
35−deriving instance Monoid f => Monoid (ForeignType f)
36−
37−makePrisms ''ForeignType
38−
3930newtype PathSegment = PathSegment { unPathSegment :: Text }
4031 deriving (Show, Eq, IsString, Monoid)
4132
@@ -43,7 +34,7 @@ makePrisms ''PathSegment
4334
4435data Arg f = Arg
4536 { _argName :: PathSegment
46− , _argType :: ForeignType f }
37+ , _argType :: f }
4738
4839deriving instance Eq f => Eq (Arg f)
4940deriving instance Show f => Show (Arg f)
@@ -130,8 +121,8 @@ data Req f = Req
130121 { _reqUrl :: Url f
131122 , _reqMethod :: HTTP.Method
132123 , _reqHeaders :: [HeaderArg f]
133− , _reqBody :: Maybe (ForeignType f)
134− , _reqReturnType :: ForeignType f
124+ , _reqBody :: Maybe f
125+ , _reqReturnType :: Maybe f
135126 , _reqFuncName :: FunctionName
136127 }
137128
@@ -140,8 +131,8 @@ deriving instance Show f => Show (Req f)
140131
141132makeLenses ''Req
142133
143−defReq :: Req Text
144−defReq = Req defUrl "GET" [] Nothing (ForeignType "") (FunctionName [])
134+defReq :: Req ftype
135+defReq = Req defUrl "GET" [] Nothing Nothing (FunctionName [])
145136
146137-- | To be used exclusively as a "negative" return type/constraint
147138-- by @'Elem`@ type family.
@@ -154,158 +145,158 @@ type family Elem (a :: *) (ls::[*]) :: Constraint where
154145
155146-- | 'HasForeignType' maps Haskell types with types in the target
156147-- language of your backend. For example, let's say you're
157−-- implementing a backend to some language __X__:
148+-- implementing a backend to some language __X__, and you want
149+-- a Text representation of each input/output type mentioned in the API:
158150--
159151-- > -- First you need to create a dummy type to parametrize your
160152-- > -- instances.
161153-- > data LangX
162154-- >
163155-- > -- Otherwise you define instances for the types you need
164−-- > instance HasForeignType LangX Int where
165−-- > typeFor _ _ = "intX"
156+-- > instance HasForeignType LangX Text Int where
157+-- > typeFor _ _ _ = "intX"
166158-- >
167159-- > -- Or for example in case of lists
168−-- > instance HasForeignType LangX a => HasForeignType LangX [a] where
169−-- > typeFor lang _ = "listX of " <> typeFor lang (Proxy :: Proxy a)
160+-- > instance HasForeignType LangX Text a => HasForeignType LangX Text [a] where
161+-- > typeFor lang type _ = "listX of " <> typeFor lang ftype (Proxy :: Proxy a)
170162--
171163-- Finally to generate list of information about all the endpoints for
172164-- an API you create a function of a form:
173165--
174−-- > getEndpoints :: (HasForeign LangX api, GenerateList (Foreign api))
175−-- > => Proxy api -> [Req]
176−-- > getEndpoints api = listFromAPI (Proxy :: Proxy LangX) api
166+-- > getEndpoints :: (HasForeign LangX Text api, GenerateList Text (Foreign Text api))
167+-- > => Proxy api -> [Req Text]
168+-- > getEndpoints api = listFromAPI (Proxy :: Proxy LangX) (Proxy :: Proxy Text) api
177169--
178170-- > -- If language __X__ is dynamically typed then you can use
179−-- > -- a predefined NoTypes parameter
180−-- > getEndpoints :: (HasForeign NoTypes api, GenerateList (Foreign api))
181−-- > => Proxy api -> [Req]
182−-- > getEndpoints api = listFromAPI (Proxy :: Proxy NoTypes) api
171+-- > -- a predefined NoTypes parameter with the () output type:
172+--
173+-- > getEndpoints :: (HasForeign NoTypes () api, GenerateList Text (Foreign () api))
174+-- > => Proxy api -> [Req ()]
175+-- > getEndpoints api = listFromAPI (Proxy :: Proxy NoTypes) (Proxy :: Proxy ()) api
183176-- >
184177--
185−class HasForeignType lang a where
186− typeFor :: Proxy lang -> Proxy a -> ForeignType Text
178+class HasForeignType lang ftype a where
179+ typeFor :: Proxy lang -> Proxy ftype -> Proxy a -> ftype
187180
188181data NoTypes
189182
190−instance HasForeignType NoTypes ftype where
191− typeFor _ _ = ForeignType empty
192−
193−type HasNoForeignType = HasForeignType NoTypes
183+instance HasForeignType NoTypes () ftype where
184+ typeFor _ _ _ = ()
194185
195−class HasForeign lang (layout :: *) where
196− type Foreign layout :: *
197− foreignFor :: Proxy lang -> Proxy layout -> Req Text -> Foreign layout
186+class HasForeign lang ftype (layout :: *) where
187+ type Foreign ftype layout :: *
188+ foreignFor :: Proxy lang -> Proxy ftype -> Proxy layout -> Req ftype -> Foreign ftype layout
198189
199−instance (HasForeign lang a, HasForeign lang b)
200− => HasForeign lang (a :<|> b) where
201− type Foreign (a :<|> b) = Foreign a :<|> Foreign b
190+instance (HasForeign lang ftype a, HasForeign lang ftype b)
191+ => HasForeign lang ftype (a :<|> b) where
192+ type Foreign ftype (a :<|> b) = Foreign ftype a :<|> Foreign ftype b
202193
203− foreignFor lang Proxy req =
204− foreignFor lang (Proxy :: Proxy a) req
205− :<|> foreignFor lang (Proxy :: Proxy b) req
194+ foreignFor lang ftype Proxy req =
195+ foreignFor lang ftype (Proxy :: Proxy a) req
196+ :<|> foreignFor lang ftype (Proxy :: Proxy b) req
206197
207−instance (KnownSymbol sym, HasForeignType lang ftype, HasForeign lang sublayout)
208− => HasForeign lang (Capture sym ftype :> sublayout) where
209− type Foreign (Capture sym a :> sublayout) = Foreign sublayout
198+instance (KnownSymbol sym, HasForeignType lang ftype t, HasForeign lang ftype sublayout)
199+ => HasForeign lang ftype (Capture sym t :> sublayout) where
200+ type Foreign ftype (Capture sym a :> sublayout) = Foreign ftype sublayout
210201
211− foreignFor lang Proxy req =
212− foreignFor lang (Proxy :: Proxy sublayout) $
202+ foreignFor lang Proxy Proxy req =
203+ foreignFor lang Proxy (Proxy :: Proxy sublayout) $
213204 req & reqUrl . path <>~ [Segment (Cap arg)]
214205 & reqFuncName . _FunctionName %~ (++ ["by", str])
215206 where
216207 str = pack . symbolVal $ (Proxy :: Proxy sym)
217− ftype = typeFor lang (Proxy :: Proxy ftype)
208+ ftype = typeFor lang (Proxy :: Proxy ftype) (Proxy :: Proxy t)
218209 arg = Arg
219210 { _argName = PathSegment str
220211 , _argType = ftype }
221212
222−instance (Elem JSON list, HasForeignType lang a, ReflectMethod method)
223− => HasForeign lang (Verb method status list a) where
224− type Foreign (Verb method status list a) = Req Text
213+instance (Elem JSON list, HasForeignType lang ftype a, ReflectMethod method)
214+ => HasForeign lang ftype (Verb method status list a) where
215+ type Foreign ftype (Verb method status list a) = Req ftype
225216
226− foreignFor lang Proxy req =
217+ foreignFor lang Proxy Proxy req =
227218 req & reqFuncName . _FunctionName %~ (methodLC :)
228219 & reqMethod .~ method
229− & reqReturnType .~ retType
220+ & reqReturnType .~ Just retType
230221 where
231− retType = typeFor lang (Proxy :: Proxy a)
222+ retType = typeFor lang (Proxy :: Proxy ftype) (Proxy :: Proxy a)
232223 method = reflectMethod (Proxy :: Proxy method)
233224 methodLC = toLower $ decodeUtf8 method
234225
235−instance (KnownSymbol sym, HasForeignType lang a, HasForeign lang sublayout)
236− => HasForeign lang (Header sym a :> sublayout) where
237− type Foreign (Header sym a :> sublayout) = Foreign sublayout
226+instance (KnownSymbol sym, HasForeignType lang ftype a, HasForeign lang ftype sublayout)
227+ => HasForeign lang ftype (Header sym a :> sublayout) where
228+ type Foreign ftype (Header sym a :> sublayout) = Foreign ftype sublayout
238229
239− foreignFor lang Proxy req =
240− foreignFor lang subP $ req & reqHeaders <>~ [HeaderArg arg]
230+ foreignFor lang Proxy Proxy req =
231+ foreignFor lang Proxy subP $ req & reqHeaders <>~ [HeaderArg arg]
241232 where
242233 hname = pack . symbolVal $ (Proxy :: Proxy sym)
243234 arg = Arg
244235 { _argName = PathSegment hname
245− , _argType = typeFor lang (Proxy :: Proxy a) }
236+ , _argType = typeFor lang (Proxy :: Proxy ftype) (Proxy :: Proxy a) }
246237 subP = Proxy :: Proxy sublayout
247238
248−instance (KnownSymbol sym, HasForeignType lang a, HasForeign lang sublayout)
249− => HasForeign lang (QueryParam sym a :> sublayout) where
250− type Foreign (QueryParam sym a :> sublayout) = Foreign sublayout
239+instance (KnownSymbol sym, HasForeignType lang ftype a, HasForeign lang ftype sublayout)
240+ => HasForeign lang ftype (QueryParam sym a :> sublayout) where
241+ type Foreign ftype (QueryParam sym a :> sublayout) = Foreign ftype sublayout
251242
252− foreignFor lang Proxy req =
253− foreignFor lang (Proxy :: Proxy sublayout) $
243+ foreignFor lang Proxy Proxy req =
244+ foreignFor lang (Proxy :: Proxy ftype) (Proxy :: Proxy sublayout) $
254245 req & reqUrl.queryStr <>~ [QueryArg arg Normal]
255246 where
256247 str = pack . symbolVal $ (Proxy :: Proxy sym)
257248 arg = Arg
258249 { _argName = PathSegment str
259− , _argType = typeFor lang (Proxy :: Proxy a) }
250+ , _argType = typeFor lang (Proxy :: Proxy ftype) (Proxy :: Proxy a) }
260251
261252instance
262− (KnownSymbol sym, HasForeignType lang [a], HasForeign lang sublayout)
263− => HasForeign lang (QueryParams sym a :> sublayout) where
264− type Foreign (QueryParams sym a :> sublayout) = Foreign sublayout
265− foreignFor lang Proxy req =
266− foreignFor lang (Proxy :: Proxy sublayout) $
253+ (KnownSymbol sym, HasForeignType lang ftype [a], HasForeign lang ftype sublayout)
254+ => HasForeign lang ftype (QueryParams sym a :> sublayout) where
255+ type Foreign ftype (QueryParams sym a :> sublayout) = Foreign ftype sublayout
256+ foreignFor lang Proxy Proxy req =
257+ foreignFor lang (Proxy :: Proxy ftype) (Proxy :: Proxy sublayout) $
267258 req & reqUrl.queryStr <>~ [QueryArg arg List]
268259 where
269260 str = pack . symbolVal $ (Proxy :: Proxy sym)
270261 arg = Arg
271262 { _argName = PathSegment str
272− , _argType = typeFor lang (Proxy :: Proxy [a]) }
263+ , _argType = typeFor lang (Proxy :: Proxy ftype) (Proxy :: Proxy [a]) }
273264
274265instance
275− (KnownSymbol sym, HasForeignType lang Bool, HasForeign lang sublayout)
276− => HasForeign lang (QueryFlag sym :> sublayout) where
277− type Foreign (QueryFlag sym :> sublayout) = Foreign sublayout
266+ (KnownSymbol sym, HasForeignType lang ftype Bool, HasForeign lang ftype sublayout)
267+ => HasForeign lang ftype (QueryFlag sym :> sublayout) where
268+ type Foreign ftype (QueryFlag sym :> sublayout) = Foreign ftype sublayout
278269
279− foreignFor lang Proxy req =
280− foreignFor lang (Proxy :: Proxy sublayout) $
270+ foreignFor lang ftype Proxy req =
271+ foreignFor lang ftype (Proxy :: Proxy sublayout) $
281272 req & reqUrl.queryStr <>~ [QueryArg arg Flag]
282273 where
283274 str = pack . symbolVal $ (Proxy :: Proxy sym)
284275 arg = Arg
285276 { _argName = PathSegment str
286− , _argType = typeFor lang (Proxy :: Proxy Bool) }
277+ , _argType = typeFor lang ftype (Proxy :: Proxy Bool) }
287278
288−instance HasForeign lang Raw where
289− type Foreign Raw = HTTP.Method -> Req Text
279+instance HasForeign lang ftype Raw where
280+ type Foreign ftype Raw = HTTP.Method -> Req ftype
290281
291− foreignFor _ Proxy req method =
282+ foreignFor _ Proxy Proxy req method =
292283 req & reqFuncName . _FunctionName %~ ((toLower $ decodeUtf8 method) :)
293284 & reqMethod .~ method
294285
295−instance (Elem JSON list, HasForeignType lang a, HasForeign lang sublayout)
296− => HasForeign lang (ReqBody list a :> sublayout) where
297− type Foreign (ReqBody list a :> sublayout) = Foreign sublayout
286+instance (Elem JSON list, HasForeignType lang ftype a, HasForeign lang ftype sublayout)
287+ => HasForeign lang ftype (ReqBody list a :> sublayout) where
288+ type Foreign ftype (ReqBody list a :> sublayout) = Foreign ftype sublayout
298289
299− foreignFor lang Proxy req =
300− foreignFor lang (Proxy :: Proxy sublayout) $
301− req & reqBody .~ (Just $ typeFor lang (Proxy :: Proxy a))
290+ foreignFor lang ftype Proxy req =
291+ foreignFor lang ftype (Proxy :: Proxy sublayout) $
292+ req & reqBody .~ (Just $ typeFor lang ftype (Proxy :: Proxy a))
302293
303−instance (KnownSymbol path, HasForeign lang sublayout)
304− => HasForeign lang (path :> sublayout) where
305− type Foreign (path :> sublayout) = Foreign sublayout
294+instance (KnownSymbol path, HasForeign lang ftype sublayout)
295+ => HasForeign lang ftype (path :> sublayout) where
296+ type Foreign ftype (path :> sublayout) = Foreign ftype sublayout
306297
307− foreignFor lang Proxy req =
308− foreignFor lang (Proxy :: Proxy sublayout) $
298+ foreignFor lang ftype Proxy req =
299+ foreignFor lang ftype (Proxy :: Proxy sublayout) $
309300 req & reqUrl . path <>~ [Segment (Static (PathSegment str))]
310301 & reqFuncName . _FunctionName %~ (++ [str])
311302 where
@@ -313,58 +304,59 @@ instance (KnownSymbol path, HasForeign lang sublayout)
313304 Data.Text.map (\c -> if c == '.' then '_' else c)
314305 . pack . symbolVal $ (Proxy :: Proxy path)
315306
316−instance HasForeign lang sublayout
317− => HasForeign lang (RemoteHost :> sublayout) where
318− type Foreign (RemoteHost :> sublayout) = Foreign sublayout
307+instance HasForeign lang ftype sublayout
308+ => HasForeign lang ftype (RemoteHost :> sublayout) where
309+ type Foreign ftype (RemoteHost :> sublayout) = Foreign ftype sublayout
319310
320− foreignFor lang Proxy req =
321− foreignFor lang (Proxy :: Proxy sublayout) req
311+ foreignFor lang ftype Proxy req =
312+ foreignFor lang ftype (Proxy :: Proxy sublayout) req
322313
323−instance HasForeign lang sublayout
324− => HasForeign lang (IsSecure :> sublayout) where
325− type Foreign (IsSecure :> sublayout) = Foreign sublayout
314+instance HasForeign lang ftype sublayout
315+ => HasForeign lang ftype (IsSecure :> sublayout) where
316+ type Foreign ftype (IsSecure :> sublayout) = Foreign ftype sublayout
326317
327− foreignFor lang Proxy req =
328− foreignFor lang (Proxy :: Proxy sublayout) req
318+ foreignFor lang ftype Proxy req =
319+ foreignFor lang ftype (Proxy :: Proxy sublayout) req
329320
330−instance HasForeign lang sublayout => HasForeign lang (Vault :> sublayout) where
331− type Foreign (Vault :> sublayout) = Foreign sublayout
321+instance HasForeign lang ftype sublayout => HasForeign lang ftype (Vault :> sublayout) where
322+ type Foreign ftype (Vault :> sublayout) = Foreign ftype sublayout
332323
333− foreignFor lang Proxy req =
334− foreignFor lang (Proxy :: Proxy sublayout) req
324+ foreignFor lang ftype Proxy req =
325+ foreignFor lang ftype (Proxy :: Proxy sublayout) req
335326
336−instance HasForeign lang sublayout =>
337− HasForeign lang (WithNamedContext name context sublayout) where
327+instance HasForeign lang ftype sublayout =>
328+ HasForeign lang ftype (WithNamedContext name context sublayout) where
338329
339− type Foreign (WithNamedContext name context sublayout) = Foreign sublayout
330+ type Foreign ftype (WithNamedContext name context sublayout) = Foreign ftype sublayout
340331
341− foreignFor lang Proxy = foreignFor lang (Proxy :: Proxy sublayout)
332+ foreignFor lang ftype Proxy = foreignFor lang ftype (Proxy :: Proxy sublayout)
342333
343−instance HasForeign lang sublayout
344− => HasForeign lang (HttpVersion :> sublayout) where
345− type Foreign (HttpVersion :> sublayout) = Foreign sublayout
334+instance HasForeign lang ftype sublayout
335+ => HasForeign lang ftype (HttpVersion :> sublayout) where
336+ type Foreign ftype (HttpVersion :> sublayout) = Foreign ftype sublayout
346337
347− foreignFor lang Proxy req =
348− foreignFor lang (Proxy :: Proxy sublayout) req
338+ foreignFor lang ftype Proxy req =
339+ foreignFor lang ftype (Proxy :: Proxy sublayout) req
349340
350341-- | Utility class used by 'listFromAPI' which computes
351342-- the data needed to generate a function for each endpoint
352343-- and hands it all back in a list.
353−class GenerateList reqs where
354− generateList :: reqs -> [Req Text]
344+class GenerateList ftype reqs where
345+ generateList :: reqs -> [Req ftype]
355346
356−instance GenerateList (Req Text) where
347+instance GenerateList ftype (Req ftype) where
357348 generateList r = [r]
358349
359−instance (GenerateList start, GenerateList rest)
360− => GenerateList (start :<|> rest) where
350+instance (GenerateList ftype start, GenerateList ftype rest)
351+ => GenerateList ftype (start :<|> rest) where
361352 generateList (start :<|> rest) = (generateList start) ++ (generateList rest)
362353
363354-- | Generate the necessary data for codegen as a list, each 'Req'
364355-- describing one endpoint from your API type.
365356listFromAPI
366− :: (HasForeign lang api, GenerateList (Foreign api))
357+ :: (HasForeign lang ftype api, GenerateList ftype (Foreign ftype api))
367358 => Proxy lang
359+ -> Proxy ftype
368360 -> Proxy api
369− -> [Req Text]
370−listFromAPI lang p = generateList (foreignFor lang p defReq)
361+ -> [Req ftype]
362+listFromAPI lang ftype p = generateList (foreignFor lang ftype p defReq)