2015-09-22 13:02:52 +02:00
|
|
|
{-# LANGUAGE CPP #-}
|
|
|
|
{-# LANGUAGE ConstraintKinds #-}
|
|
|
|
{-# LANGUAGE DataKinds #-}
|
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
2015-09-23 20:39:46 +02:00
|
|
|
#if !MIN_VERSION_base(4,8,0)
|
|
|
|
{-# LANGUAGE NullaryTypeClasses #-}
|
|
|
|
#endif
|
2015-09-22 13:02:52 +02:00
|
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
|
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
|
|
{-# LANGUAGE TypeOperators #-}
|
|
|
|
{-# LANGUAGE UndecidableInstances #-}
|
2015-10-02 10:23:57 +02:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2016-01-06 18:20:20 +01:00
|
|
|
{-# LANGUAGE PolyKinds #-}
|
2015-09-21 12:31:00 +02:00
|
|
|
|
|
|
|
-- | Generalizes all the data needed to make code generation work with
|
|
|
|
-- arbitrary programming languages.
|
2015-11-16 18:40:15 +01:00
|
|
|
module Servant.Foreign.Internal where
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
import Control.Lens (makeLenses, makePrisms, (%~), (&), (.~), (<>~))
|
|
|
|
import qualified Data.Char as C
|
2015-10-08 23:33:32 +02:00
|
|
|
import Data.Proxy
|
|
|
|
import Data.Text
|
2016-02-11 11:41:34 +01:00
|
|
|
import Data.Text.Encoding (decodeUtf8)
|
|
|
|
import GHC.Exts (Constraint)
|
2015-10-08 23:33:32 +02:00
|
|
|
import GHC.TypeLits
|
2016-02-11 11:41:34 +01:00
|
|
|
import qualified Network.HTTP.Types as HTTP
|
|
|
|
import Prelude hiding (concat)
|
2015-10-08 23:33:32 +02:00
|
|
|
import Servant.API
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
type FunctionName = [Text]
|
|
|
|
|
2015-09-21 12:31:00 +02:00
|
|
|
-- | Function name builder that simply concat each part together
|
2015-10-02 10:23:57 +02:00
|
|
|
concatCase :: FunctionName -> Text
|
2015-09-21 12:31:00 +02:00
|
|
|
concatCase = concat
|
|
|
|
|
|
|
|
-- | Function name builder using the snake_case convention.
|
|
|
|
-- each part is separated by a single underscore character.
|
2015-10-02 10:23:57 +02:00
|
|
|
snakeCase :: FunctionName -> Text
|
2015-09-21 12:31:00 +02:00
|
|
|
snakeCase = intercalate "_"
|
|
|
|
|
|
|
|
-- | Function name builder using the CamelCase convention.
|
|
|
|
-- each part begins with an upper case character.
|
2015-10-02 10:23:57 +02:00
|
|
|
camelCase :: FunctionName -> Text
|
2015-11-04 12:16:39 +01:00
|
|
|
camelCase = camelCase' . Prelude.map (replace "-" "")
|
|
|
|
where camelCase' [] = ""
|
|
|
|
camelCase' (p:ps) = concat $ p : Prelude.map capitalize ps
|
|
|
|
capitalize "" = ""
|
|
|
|
capitalize name = C.toUpper (Data.Text.head name) `cons` Data.Text.tail name
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-11-28 09:13:26 +01:00
|
|
|
type ForeignType = Text
|
2016-02-11 11:41:34 +01:00
|
|
|
|
2015-11-28 09:13:26 +01:00
|
|
|
type Arg = (Text, ForeignType)
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
data SegmentType
|
|
|
|
= Static Text
|
|
|
|
-- ^ a static path segment. like "/foo"
|
|
|
|
| Cap Arg
|
|
|
|
-- ^ a capture. like "/:userid"
|
2015-09-21 12:31:00 +02:00
|
|
|
deriving (Eq, Show)
|
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
makePrisms ''SegmentType
|
|
|
|
|
|
|
|
newtype Segment = Segment { unSegment :: SegmentType }
|
2015-09-21 12:31:00 +02:00
|
|
|
deriving (Eq, Show)
|
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
makePrisms ''Segment
|
|
|
|
|
2015-09-21 12:31:00 +02:00
|
|
|
type Path = [Segment]
|
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
data ArgType
|
|
|
|
= Normal
|
2015-09-21 12:31:00 +02:00
|
|
|
| Flag
|
|
|
|
| List
|
|
|
|
deriving (Eq, Show)
|
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
makePrisms ''ArgType
|
|
|
|
|
2015-09-21 12:31:00 +02:00
|
|
|
data QueryArg = QueryArg
|
|
|
|
{ _argName :: Arg
|
|
|
|
, _argType :: ArgType
|
|
|
|
} deriving (Eq, Show)
|
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
makeLenses ''QueryArg
|
|
|
|
|
2015-09-21 12:31:00 +02:00
|
|
|
data HeaderArg = HeaderArg
|
2016-02-11 11:41:34 +01:00
|
|
|
{ headerArg :: Arg }
|
2015-09-21 12:31:00 +02:00
|
|
|
| ReplaceHeaderArg
|
2016-02-11 11:41:34 +01:00
|
|
|
{ headerArg :: Arg
|
|
|
|
, headerPattern :: Text
|
|
|
|
} deriving (Eq, Show)
|
2015-09-22 12:17:43 +02:00
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
makeLenses ''HeaderArg
|
|
|
|
|
|
|
|
makePrisms ''HeaderArg
|
2015-09-21 12:31:00 +02:00
|
|
|
|
|
|
|
data Url = Url
|
|
|
|
{ _path :: Path
|
|
|
|
, _queryStr :: [QueryArg]
|
|
|
|
} deriving (Eq, Show)
|
|
|
|
|
|
|
|
defUrl :: Url
|
|
|
|
defUrl = Url [] []
|
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
makeLenses ''Url
|
2015-09-21 12:31:00 +02:00
|
|
|
|
|
|
|
data Req = Req
|
2015-11-28 09:13:26 +01:00
|
|
|
{ _reqUrl :: Url
|
2016-01-06 18:20:20 +01:00
|
|
|
, _reqMethod :: HTTP.Method
|
2015-11-28 09:13:26 +01:00
|
|
|
, _reqHeaders :: [HeaderArg]
|
|
|
|
, _reqBody :: Maybe ForeignType
|
|
|
|
, _reqReturnType :: ForeignType
|
2016-02-11 11:41:34 +01:00
|
|
|
, _reqFuncName :: FunctionName
|
2015-09-21 12:31:00 +02:00
|
|
|
} deriving (Eq, Show)
|
|
|
|
|
|
|
|
makeLenses ''Req
|
|
|
|
|
|
|
|
isCapture :: Segment -> Bool
|
2015-10-08 23:33:32 +02:00
|
|
|
isCapture (Segment (Cap _)) = True
|
|
|
|
isCapture _ = False
|
2015-09-21 12:31:00 +02:00
|
|
|
|
|
|
|
captureArg :: Segment -> Arg
|
2015-10-08 23:33:32 +02:00
|
|
|
captureArg (Segment (Cap s)) = s
|
|
|
|
captureArg _ = error "captureArg called on non capture"
|
2015-09-21 12:31:00 +02:00
|
|
|
|
|
|
|
defReq :: Req
|
2015-11-28 09:13:26 +01:00
|
|
|
defReq = Req defUrl "GET" [] Nothing "" []
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-09-22 13:02:52 +02:00
|
|
|
-- | To be used exclusively as a "negative" return type/constraint
|
|
|
|
-- by @'Elem`@ type family.
|
|
|
|
class NotFound
|
|
|
|
|
2015-09-21 12:31:00 +02:00
|
|
|
type family Elem (a :: *) (ls::[*]) :: Constraint where
|
2015-09-22 13:02:52 +02:00
|
|
|
Elem a '[] = NotFound
|
2015-09-21 12:31:00 +02:00
|
|
|
Elem a (a ': list) = ()
|
|
|
|
Elem a (b ': list) = Elem a list
|
|
|
|
|
2015-12-02 15:10:30 +01:00
|
|
|
-- | 'HasForeignType' maps Haskell types with types in the target
|
|
|
|
-- language of your backend. For example, let's say you're
|
|
|
|
-- implementing a backend to some language __X__:
|
|
|
|
--
|
|
|
|
-- > -- First you need to create a dummy type to parametrize your
|
|
|
|
-- > -- instances.
|
|
|
|
-- > data LangX
|
|
|
|
-- >
|
|
|
|
-- > -- Otherwise you define instances for the types you need
|
|
|
|
-- > instance HasForeignType LangX Int where
|
|
|
|
-- > typeFor _ _ = "intX"
|
|
|
|
-- >
|
|
|
|
-- > -- Or for example in case of lists
|
|
|
|
-- > instance HasForeignType LangX a => HasForeignType LangX [a] where
|
|
|
|
-- > typeFor lang _ = "listX of " <> typeFor lang (Proxy :: Proxy a)
|
|
|
|
--
|
|
|
|
-- Finally to generate list of information about all the endpoints for
|
|
|
|
-- an API you create a function of a form:
|
|
|
|
--
|
|
|
|
-- > getEndpoints :: (HasForeign LangX api, GenerateList (Foreign api))
|
|
|
|
-- > => Proxy api -> [Req]
|
|
|
|
-- > getEndpoints api = listFromAPI (Proxy :: Proxy LangX) api
|
|
|
|
--
|
2015-12-02 16:56:56 +01:00
|
|
|
-- > -- If language __X__ is dynamically typed then you can use
|
|
|
|
-- > -- a predefined NoTypes parameter
|
|
|
|
-- > getEndpoints :: (HasForeign NoTypes api, GenerateList (Foreign api))
|
|
|
|
-- > => Proxy api -> [Req]
|
|
|
|
-- > getEndpoints api = listFromAPI (Proxy :: Proxy NoTypes) api
|
|
|
|
-- >
|
|
|
|
--
|
2015-11-29 05:53:50 +01:00
|
|
|
class HasForeignType lang a where
|
2016-02-11 11:41:34 +01:00
|
|
|
typeFor :: Proxy lang -> Proxy a -> ForeignType
|
2015-11-28 09:13:26 +01:00
|
|
|
|
2015-12-02 16:56:56 +01:00
|
|
|
data NoTypes
|
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
instance HasForeignType NoTypes ftype where
|
|
|
|
typeFor _ _ = empty
|
|
|
|
|
|
|
|
type HasNoForeignType = HasForeignType NoTypes
|
2015-12-02 16:56:56 +01:00
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
class HasForeign lang (layout :: *) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign layout :: *
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor :: Proxy lang -> Proxy layout -> Req -> Foreign layout
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
instance (HasForeign lang a, HasForeign lang b)
|
2016-02-11 11:41:34 +01:00
|
|
|
=> HasForeign lang (a :<|> b) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (a :<|> b) = Foreign a :<|> Foreign b
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy a) req
|
|
|
|
:<|> foreignFor lang (Proxy :: Proxy b) req
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
instance (KnownSymbol sym, HasForeignType lang ftype, HasForeign lang sublayout)
|
|
|
|
=> HasForeign lang (Capture sym ftype :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (Capture sym a :> sublayout) = Foreign sublayout
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy sublayout) $
|
2015-11-28 09:13:26 +01:00
|
|
|
req & reqUrl.path <>~ [Segment (Cap arg)]
|
2016-02-11 11:41:34 +01:00
|
|
|
& reqFuncName %~ (++ ["by", str])
|
2015-11-28 09:13:26 +01:00
|
|
|
where
|
2016-02-11 11:41:34 +01:00
|
|
|
str = pack . symbolVal $ (Proxy :: Proxy sym)
|
|
|
|
arg = (str, typeFor lang (Proxy :: Proxy ftype))
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2016-01-06 18:20:20 +01:00
|
|
|
instance (Elem JSON list, HasForeignType lang a, ReflectMethod method)
|
2016-02-11 11:41:34 +01:00
|
|
|
=> HasForeign lang (Verb method status list a) where
|
2016-01-06 18:20:20 +01:00
|
|
|
type Foreign (Verb method status list a) = Req
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
2016-02-11 11:41:34 +01:00
|
|
|
req & reqFuncName %~ (methodLC :)
|
2016-01-06 18:20:20 +01:00
|
|
|
& reqMethod .~ method
|
2015-11-28 09:13:26 +01:00
|
|
|
& reqReturnType .~ retType
|
|
|
|
where
|
2016-02-11 11:41:34 +01:00
|
|
|
retType = typeFor lang (Proxy :: Proxy a)
|
|
|
|
method = reflectMethod (Proxy :: Proxy method)
|
|
|
|
methodLC = toLower $ decodeUtf8 method
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
instance (KnownSymbol sym, HasForeignType lang a, HasForeign lang sublayout)
|
2016-02-11 11:41:34 +01:00
|
|
|
=> HasForeign lang (Header sym a :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (Header sym a :> sublayout) = Foreign sublayout
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang subP $ req
|
2015-11-28 09:13:26 +01:00
|
|
|
& reqHeaders <>~ [HeaderArg arg]
|
|
|
|
where
|
2016-02-11 11:41:34 +01:00
|
|
|
hname = pack . symbolVal $ (Proxy :: Proxy sym)
|
|
|
|
arg = (hname, typeFor lang (Proxy :: Proxy a))
|
|
|
|
subP = Proxy :: Proxy sublayout
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
instance (KnownSymbol sym, HasForeignType lang a, HasForeign lang sublayout)
|
2016-02-11 11:41:34 +01:00
|
|
|
=> HasForeign lang (QueryParam sym a :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (QueryParam sym a :> sublayout) = Foreign sublayout
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy sublayout) $
|
2015-11-28 09:13:26 +01:00
|
|
|
req & reqUrl.queryStr <>~ [QueryArg arg Normal]
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-11-28 09:13:26 +01:00
|
|
|
where
|
2016-02-11 11:41:34 +01:00
|
|
|
str = pack . symbolVal $ (Proxy :: Proxy sym)
|
|
|
|
arg = (str, typeFor lang (Proxy :: Proxy a))
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
instance
|
|
|
|
(KnownSymbol sym, HasForeignType lang [a], HasForeign lang sublayout)
|
|
|
|
=> HasForeign lang (QueryParams sym a :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (QueryParams sym a :> sublayout) = Foreign sublayout
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy sublayout) $
|
2015-11-28 09:13:26 +01:00
|
|
|
req & reqUrl.queryStr <>~ [QueryArg arg List]
|
|
|
|
where
|
2016-02-11 11:41:34 +01:00
|
|
|
str = pack . symbolVal $ (Proxy :: Proxy sym)
|
|
|
|
arg = (str, typeFor lang (Proxy :: Proxy [a]))
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
instance
|
|
|
|
(KnownSymbol sym, HasForeignType lang Bool, HasForeign lang sublayout)
|
|
|
|
=> HasForeign lang (QueryFlag sym :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (QueryFlag sym :> sublayout) = Foreign sublayout
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy sublayout) $
|
2015-11-28 09:13:26 +01:00
|
|
|
req & reqUrl.queryStr <>~ [QueryArg arg Flag]
|
|
|
|
where
|
2016-02-11 11:41:34 +01:00
|
|
|
str = pack . symbolVal $ (Proxy :: Proxy sym)
|
|
|
|
arg = (str, typeFor lang (Proxy :: Proxy Bool))
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
instance HasForeign lang Raw where
|
2016-01-06 18:20:20 +01:00
|
|
|
type Foreign Raw = HTTP.Method -> Req
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor _ Proxy req method =
|
2016-02-11 11:41:34 +01:00
|
|
|
req & reqFuncName %~ ((toLower $ decodeUtf8 method) :)
|
2015-09-21 12:31:00 +02:00
|
|
|
& reqMethod .~ method
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
instance (Elem JSON list, HasForeignType lang a, HasForeign lang sublayout)
|
|
|
|
=> HasForeign lang (ReqBody list a :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (ReqBody list a :> sublayout) = Foreign sublayout
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy sublayout) $
|
|
|
|
req & reqBody .~ (Just $ typeFor lang (Proxy :: Proxy a))
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
instance (KnownSymbol path, HasForeign lang sublayout)
|
|
|
|
=> HasForeign lang (path :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (path :> sublayout) = Foreign sublayout
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy sublayout) $
|
2015-10-08 23:33:32 +02:00
|
|
|
req & reqUrl.path <>~ [Segment (Static str)]
|
2016-02-11 11:41:34 +01:00
|
|
|
& reqFuncName %~ (++ [str])
|
2015-11-28 09:13:26 +01:00
|
|
|
where
|
2016-02-11 11:41:34 +01:00
|
|
|
str =
|
|
|
|
Data.Text.map (\c -> if c == '.' then '_' else c)
|
|
|
|
. pack . symbolVal $ (Proxy :: Proxy path)
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
instance HasForeign lang sublayout
|
|
|
|
=> HasForeign lang (RemoteHost :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (RemoteHost :> sublayout) = Foreign sublayout
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy sublayout) req
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
instance HasForeign lang sublayout
|
|
|
|
=> HasForeign lang (IsSecure :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (IsSecure :> sublayout) = Foreign sublayout
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy sublayout) req
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
instance HasForeign lang sublayout => HasForeign lang (Vault :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (Vault :> sublayout) = Foreign sublayout
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy sublayout) req
|
2015-09-21 12:31:00 +02:00
|
|
|
|
2016-01-18 21:27:19 +01:00
|
|
|
instance HasForeign lang sublayout =>
|
|
|
|
HasForeign lang (WithNamedConfig name config sublayout) where
|
|
|
|
|
|
|
|
type Foreign (WithNamedConfig name config sublayout) = Foreign sublayout
|
|
|
|
|
|
|
|
foreignFor lang Proxy = foreignFor lang (Proxy :: Proxy sublayout)
|
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
instance HasForeign lang sublayout
|
|
|
|
=> HasForeign lang (HttpVersion :> sublayout) where
|
2015-09-21 12:31:00 +02:00
|
|
|
type Foreign (HttpVersion :> sublayout) = Foreign sublayout
|
|
|
|
|
2015-11-29 05:53:50 +01:00
|
|
|
foreignFor lang Proxy req =
|
|
|
|
foreignFor lang (Proxy :: Proxy sublayout) req
|
2015-12-02 12:21:37 +01:00
|
|
|
|
|
|
|
-- | Utility class used by 'listFromAPI' which computes
|
|
|
|
-- the data needed to generate a function for each endpoint
|
|
|
|
-- and hands it all back in a list.
|
|
|
|
class GenerateList reqs where
|
|
|
|
generateList :: reqs -> [Req]
|
|
|
|
|
|
|
|
instance GenerateList Req where
|
|
|
|
generateList r = [r]
|
|
|
|
|
2016-02-11 11:41:34 +01:00
|
|
|
instance (GenerateList start, GenerateList rest)
|
|
|
|
=> GenerateList (start :<|> rest) where
|
2015-12-02 12:21:37 +01:00
|
|
|
generateList (start :<|> rest) = (generateList start) ++ (generateList rest)
|
|
|
|
|
|
|
|
-- | Generate the necessary data for codegen as a list, each 'Req'
|
|
|
|
-- describing one endpoint from your API type.
|
2016-02-11 11:41:34 +01:00
|
|
|
listFromAPI
|
|
|
|
:: (HasForeign lang api, GenerateList (Foreign api))
|
|
|
|
=> Proxy lang
|
|
|
|
-> Proxy api
|
|
|
|
-> [Req]
|
2015-12-02 12:21:37 +01:00
|
|
|
listFromAPI lang p = generateList (foreignFor lang p defReq)
|