git.iko.soy/typeable/servant
on master help sign in
Make servant-foreign code nicer
e6e13fdDenis Redozubov
servant-foreign/src/Servant/Foreign.hs+35−21
@@ -1,36 +1,50 @@
1-- | Generalizes all the data needed to make code generation work with
1-- | Generalizes all the data needed to make code generation work with
2-- arbitrary programming languages.
2-- arbitrary programming languages.
3module Servant.Foreign
3module Servant.Foreign
4− ( HasForeign(..)
4+ ( ArgType(..)
5− , HasForeignType(..)
5+ , HeaderArg(..)
6+ , QueryArg(..)
7+ , Req(..)
6 , Segment(..)
8 , Segment(..)
7 , SegmentType(..)
9 , SegmentType(..)
10+ , Url(..)
11+ -- aliases
12+ , Path
13+ , ForeignType
14+ , Arg
8 , FunctionName
15 , FunctionName
9− , QueryArg(..)
10− , HeaderArg(..)
11− , ArgType(..)
12− , Req
13− , captureArg
14− , defReq
15− , concatCase
16− , snakeCase
17− , camelCase
18− -- lenses
16+ -- lenses
19− , argType
20− , argName
21− , isCapture
22− , funcName
23− , path
24 , reqUrl
17 , reqUrl
25− , reqBody
26− , reqHeaders
27 , reqMethod
18 , reqMethod
19+ , reqHeaders
20+ , reqBody
28 , reqReturnType
21 , reqReturnType
29− , segment
22+ , reqFuncName
23+ , path
30 , queryStr
24 , queryStr
31− , listFromAPI
25+ , argName
26+ , argType
27+ -- prisms
28+ , _HeaderArg
29+ , _ReplaceHeaderArg
30+ , _Static
31+ , _Cap
32+ , _Normal
33+ , _Flag
34+ , _List
35+ -- rest of it
36+ , HasForeign(..)
37+ , HasForeignType(..)
38+ , HasNoForeignType
32 , GenerateList(..)
39 , GenerateList(..)
33 , NoTypes
40 , NoTypes
41+ , captureArg
42+ , isCapture
43+ , concatCase
44+ , snakeCase
45+ , camelCase
46+ , defReq
47+ , listFromAPI
34 -- re-exports
48 -- re-exports
35 , module Servant.API
49 , module Servant.API
36 ) where
50 ) where
servant-foreign/src/Servant/Foreign/Internal.hs+85−65
@@ -19,17 +19,19 @@
19-- arbitrary programming languages.
19-- arbitrary programming languages.
20module Servant.Foreign.Internal where
20module Servant.Foreign.Internal where
21
21
22−import Control.Lens (makeLenses, (%~), (&), (.~), (<>~))
22+import Control.Lens (makeLenses, makePrisms, (%~), (&), (.~), (<>~))
23−import qualified Data.Char as C
23+import qualified Data.Char as C
24import Data.Proxy
24import Data.Proxy
25import Data.Text
25import Data.Text
26−import Data.Text.Encoding (decodeUtf8)
26+import Data.Text.Encoding (decodeUtf8)
27−import GHC.Exts (Constraint)
27+import GHC.Exts (Constraint)
28import GHC.TypeLits
28import GHC.TypeLits
29−import qualified Network.HTTP.Types as HTTP
29+import qualified Network.HTTP.Types as HTTP
30−import Prelude hiding (concat)
30+import Prelude hiding (concat)
31import Servant.API
31import Servant.API
32
32
33+type FunctionName = [Text]
34+
33-- | Function name builder that simply concat each part together
35-- | Function name builder that simply concat each part together
34concatCase :: FunctionName -> Text
36concatCase :: FunctionName -> Text
35concatCase = concat
37concatCase = concat
@@ -49,36 +51,50 @@ camelCase = camelCase' . Prelude.map (replace "-" "")
49 capitalize name = C.toUpper (Data.Text.head name) `cons` Data.Text.tail name
51 capitalize name = C.toUpper (Data.Text.head name) `cons` Data.Text.tail name
50
52
51type ForeignType = Text
53type ForeignType = Text
54+
52type Arg = (Text, ForeignType)
55type Arg = (Text, ForeignType)
53
56
54−newtype Segment = Segment { _segment :: SegmentType }
57+data SegmentType
58+ = Static Text
59+ -- ^ a static path segment. like "/foo"
60+ | Cap Arg
61+ -- ^ a capture. like "/:userid"
55 deriving (Eq, Show)
62 deriving (Eq, Show)
56
63
57−data SegmentType = Static Text -- ^ a static path segment. like "/foo"
64+makePrisms ''SegmentType
58− | Cap Arg -- ^ a capture. like "/:userid"
65+
66+newtype Segment = Segment { unSegment :: SegmentType }
59 deriving (Eq, Show)
67 deriving (Eq, Show)
60
68
69+makePrisms ''Segment
70+
61type Path = [Segment]
71type Path = [Segment]
62
72
63−data ArgType =
73+data ArgType
64− Normal
74+ = Normal
65 | Flag
75 | Flag
66 | List
76 | List
67 deriving (Eq, Show)
77 deriving (Eq, Show)
68
78
79+makePrisms ''ArgType
80+
69data QueryArg = QueryArg
81data QueryArg = QueryArg
70 { _argName :: Arg
82 { _argName :: Arg
71 , _argType :: ArgType
83 , _argType :: ArgType
72 } deriving (Eq, Show)
84 } deriving (Eq, Show)
73
85
86+makeLenses ''QueryArg
87+
74data HeaderArg = HeaderArg
88data HeaderArg = HeaderArg
75− { headerArg :: Arg
89+ { headerArg :: Arg }
76− }
77 | ReplaceHeaderArg
90 | ReplaceHeaderArg
78− { headerArg :: Arg
91+ { headerArg :: Arg
79− , headerPattern :: Text
92+ , headerPattern :: Text
80− } deriving (Eq, Show)
93+ } deriving (Eq, Show)
81
94
95+makeLenses ''HeaderArg
96+
97+makePrisms ''HeaderArg
82
98
83data Url = Url
99data Url = Url
84 { _path :: Path
100 { _path :: Path
@@ -88,7 +104,7 @@ data Url = Url
88defUrl :: Url
104defUrl :: Url
89defUrl = Url [] []
105defUrl = Url [] []
90
106
91−type FunctionName = [Text]
107+makeLenses ''Url
92
108
93data Req = Req
109data Req = Req
94 { _reqUrl :: Url
110 { _reqUrl :: Url
@@ -96,12 +112,9 @@ data Req = Req
96 , _reqHeaders :: [HeaderArg]
112 , _reqHeaders :: [HeaderArg]
97 , _reqBody :: Maybe ForeignType
113 , _reqBody :: Maybe ForeignType
98 , _reqReturnType :: ForeignType
114 , _reqReturnType :: ForeignType
99− , _funcName :: FunctionName
115+ , _reqFuncName :: FunctionName
100 } deriving (Eq, Show)
116 } deriving (Eq, Show)
101
117
102−makeLenses ''QueryArg
103−makeLenses ''Segment
104−makeLenses ''Url
105makeLenses ''Req
118makeLenses ''Req
106
119
107isCapture :: Segment -> Bool
120isCapture :: Segment -> Bool
@@ -155,66 +168,66 @@ type family Elem (a :: *) (ls::[*]) :: Constraint where
155-- >
168-- >
156--
169--
157class HasForeignType lang a where
170class HasForeignType lang a where
158− typeFor :: Proxy lang -> Proxy a -> ForeignType
171+ typeFor :: Proxy lang -> Proxy a -> ForeignType
159
172
160data NoTypes
173data NoTypes
161
174
162−instance HasForeignType NoTypes a where
175+instance HasForeignType NoTypes ftype where
163− typeFor _ _ = empty
176+ typeFor _ _ = empty
177+
178+type HasNoForeignType = HasForeignType NoTypes
164
179
165class HasForeign lang (layout :: *) where
180class HasForeign lang (layout :: *) where
166 type Foreign layout :: *
181 type Foreign layout :: *
167 foreignFor :: Proxy lang -> Proxy layout -> Req -> Foreign layout
182 foreignFor :: Proxy lang -> Proxy layout -> Req -> Foreign layout
168
183
169instance (HasForeign lang a, HasForeign lang b)
184instance (HasForeign lang a, HasForeign lang b)
170− => HasForeign lang (a :<|> b) where
185+ => HasForeign lang (a :<|> b) where
171 type Foreign (a :<|> b) = Foreign a :<|> Foreign b
186 type Foreign (a :<|> b) = Foreign a :<|> Foreign b
172
187
173 foreignFor lang Proxy req =
188 foreignFor lang Proxy req =
174 foreignFor lang (Proxy :: Proxy a) req
189 foreignFor lang (Proxy :: Proxy a) req
175 :<|> foreignFor lang (Proxy :: Proxy b) req
190 :<|> foreignFor lang (Proxy :: Proxy b) req
176
191
177−instance (KnownSymbol sym, HasForeignType lang a, HasForeign lang sublayout)
192+instance (KnownSymbol sym, HasForeignType lang ftype, HasForeign lang sublayout)
178− => HasForeign lang (Capture sym a :> sublayout) where
193+ => HasForeign lang (Capture sym ftype :> sublayout) where
179 type Foreign (Capture sym a :> sublayout) = Foreign sublayout
194 type Foreign (Capture sym a :> sublayout) = Foreign sublayout
180
195
181 foreignFor lang Proxy req =
196 foreignFor lang Proxy req =
182 foreignFor lang (Proxy :: Proxy sublayout) $
197 foreignFor lang (Proxy :: Proxy sublayout) $
183 req & reqUrl.path <>~ [Segment (Cap arg)]
198 req & reqUrl.path <>~ [Segment (Cap arg)]
184− & funcName %~ (++ ["by", str])
199+ & reqFuncName %~ (++ ["by", str])
185−
186 where
200 where
187− str = pack . symbolVal $ (Proxy :: Proxy sym)
201+ str = pack . symbolVal $ (Proxy :: Proxy sym)
188− arg = (str, typeFor lang (Proxy :: Proxy a))
202+ arg = (str, typeFor lang (Proxy :: Proxy ftype))
189
203
190instance (Elem JSON list, HasForeignType lang a, ReflectMethod method)
204instance (Elem JSON list, HasForeignType lang a, ReflectMethod method)
191− => HasForeign lang (Verb method status list a) where
205+ => HasForeign lang (Verb method status list a) where
192 type Foreign (Verb method status list a) = Req
206 type Foreign (Verb method status list a) = Req
193
207
194 foreignFor lang Proxy req =
208 foreignFor lang Proxy req =
195− req & funcName %~ (methodLC :)
209+ req & reqFuncName %~ (methodLC :)
196 & reqMethod .~ method
210 & reqMethod .~ method
197 & reqReturnType .~ retType
211 & reqReturnType .~ retType
198 where
212 where
199− retType = typeFor lang (Proxy :: Proxy a)
213+ retType = typeFor lang (Proxy :: Proxy a)
200− method = reflectMethod (Proxy :: Proxy method)
214+ method = reflectMethod (Proxy :: Proxy method)
201− methodLC = toLower $ decodeUtf8 method
215+ methodLC = toLower $ decodeUtf8 method
202
216
203instance (KnownSymbol sym, HasForeignType lang a, HasForeign lang sublayout)
217instance (KnownSymbol sym, HasForeignType lang a, HasForeign lang sublayout)
204− => HasForeign lang (Header sym a :> sublayout) where
218+ => HasForeign lang (Header sym a :> sublayout) where
205 type Foreign (Header sym a :> sublayout) = Foreign sublayout
219 type Foreign (Header sym a :> sublayout) = Foreign sublayout
206
220
207 foreignFor lang Proxy req =
221 foreignFor lang Proxy req =
208 foreignFor lang subP $ req
222 foreignFor lang subP $ req
209 & reqHeaders <>~ [HeaderArg arg]
223 & reqHeaders <>~ [HeaderArg arg]
210−
211 where
224 where
212− hname = pack . symbolVal $ (Proxy :: Proxy sym)
225+ hname = pack . symbolVal $ (Proxy :: Proxy sym)
213− arg = (hname, typeFor lang (Proxy :: Proxy a))
226+ arg = (hname, typeFor lang (Proxy :: Proxy a))
214− subP = Proxy :: Proxy sublayout
227+ subP = Proxy :: Proxy sublayout
215
228
216instance (KnownSymbol sym, HasForeignType lang a, HasForeign lang sublayout)
229instance (KnownSymbol sym, HasForeignType lang a, HasForeign lang sublayout)
217− => HasForeign lang (QueryParam sym a :> sublayout) where
230+ => HasForeign lang (QueryParam sym a :> sublayout) where
218 type Foreign (QueryParam sym a :> sublayout) = Foreign sublayout
231 type Foreign (QueryParam sym a :> sublayout) = Foreign sublayout
219
232
220 foreignFor lang Proxy req =
233 foreignFor lang Proxy req =
@@ -222,38 +235,37 @@ instance (KnownSymbol sym, HasForeignType lang a, HasForeign lang sublayout)
222 req & reqUrl.queryStr <>~ [QueryArg arg Normal]
235 req & reqUrl.queryStr <>~ [QueryArg arg Normal]
223
236
224 where
237 where
225− str = pack . symbolVal $ (Proxy :: Proxy sym)
238+ str = pack . symbolVal $ (Proxy :: Proxy sym)
226− arg = (str, typeFor lang (Proxy :: Proxy a))
239+ arg = (str, typeFor lang (Proxy :: Proxy a))
227
240
241+instance
228−instance (KnownSymbol sym, HasForeignType lang [a], HasForeign lang sublayout)
242+ (KnownSymbol sym, HasForeignType lang [a], HasForeign lang sublayout)
229− => HasForeign lang (QueryParams sym a :> sublayout) where
243+ => HasForeign lang (QueryParams sym a :> sublayout) where
230 type Foreign (QueryParams sym a :> sublayout) = Foreign sublayout
244 type Foreign (QueryParams sym a :> sublayout) = Foreign sublayout
231−
232 foreignFor lang Proxy req =
245 foreignFor lang Proxy req =
233 foreignFor lang (Proxy :: Proxy sublayout) $
246 foreignFor lang (Proxy :: Proxy sublayout) $
234 req & reqUrl.queryStr <>~ [QueryArg arg List]
247 req & reqUrl.queryStr <>~ [QueryArg arg List]
235−
236 where
248 where
237− str = pack . symbolVal $ (Proxy :: Proxy sym)
249+ str = pack . symbolVal $ (Proxy :: Proxy sym)
238− arg = (str, typeFor lang (Proxy :: Proxy [a]))
250+ arg = (str, typeFor lang (Proxy :: Proxy [a]))
239
251
252+instance
240−instance (KnownSymbol sym, HasForeignType lang a, a ~ Bool, HasForeign lang sublayout)
253+ (KnownSymbol sym, HasForeignType lang Bool, HasForeign lang sublayout)
241− => HasForeign lang (QueryFlag sym :> sublayout) where
254+ => HasForeign lang (QueryFlag sym :> sublayout) where
242 type Foreign (QueryFlag sym :> sublayout) = Foreign sublayout
255 type Foreign (QueryFlag sym :> sublayout) = Foreign sublayout
243
256
244 foreignFor lang Proxy req =
257 foreignFor lang Proxy req =
245 foreignFor lang (Proxy :: Proxy sublayout) $
258 foreignFor lang (Proxy :: Proxy sublayout) $
246 req & reqUrl.queryStr <>~ [QueryArg arg Flag]
259 req & reqUrl.queryStr <>~ [QueryArg arg Flag]
247−
248 where
260 where
249− str = pack . symbolVal $ (Proxy :: Proxy sym)
261+ str = pack . symbolVal $ (Proxy :: Proxy sym)
250− arg = (str, typeFor lang (Proxy :: Proxy a))
262+ arg = (str, typeFor lang (Proxy :: Proxy Bool))
251
263
252instance HasForeign lang Raw where
264instance HasForeign lang Raw where
253 type Foreign Raw = HTTP.Method -> Req
265 type Foreign Raw = HTTP.Method -> Req
254
266
255 foreignFor _ Proxy req method =
267 foreignFor _ Proxy req method =
256− req & funcName %~ ((toLower $ decodeUtf8 method) :)
268+ req & reqFuncName %~ ((toLower $ decodeUtf8 method) :)
257 & reqMethod .~ method
269 & reqMethod .~ method
258
270
259instance (Elem JSON list, HasForeignType lang a, HasForeign lang sublayout)
271instance (Elem JSON list, HasForeignType lang a, HasForeign lang sublayout)
@@ -271,19 +283,21 @@ instance (KnownSymbol path, HasForeign lang sublayout)
271 foreignFor lang Proxy req =
283 foreignFor lang Proxy req =
272 foreignFor lang (Proxy :: Proxy sublayout) $
284 foreignFor lang (Proxy :: Proxy sublayout) $
273 req & reqUrl.path <>~ [Segment (Static str)]
285 req & reqUrl.path <>~ [Segment (Static str)]
274− & funcName %~ (++ [str])
286+ & reqFuncName %~ (++ [str])
275−
276 where
287 where
288+ str =
277− str = Data.Text.map (\c -> if c == '.' then '_' else c)
289+ Data.Text.map (\c -> if c == '.' then '_' else c)
278− . pack . symbolVal $ (Proxy :: Proxy path)
290+ . pack . symbolVal $ (Proxy :: Proxy path)
279
291
292+instance HasForeign lang sublayout
280−instance HasForeign lang sublayout => HasForeign lang (RemoteHost :> sublayout) where
293+ => HasForeign lang (RemoteHost :> sublayout) where
281 type Foreign (RemoteHost :> sublayout) = Foreign sublayout
294 type Foreign (RemoteHost :> sublayout) = Foreign sublayout
282
295
283 foreignFor lang Proxy req =
296 foreignFor lang Proxy req =
284 foreignFor lang (Proxy :: Proxy sublayout) req
297 foreignFor lang (Proxy :: Proxy sublayout) req
285
298
299+instance HasForeign lang sublayout
286−instance HasForeign lang sublayout => HasForeign lang (IsSecure :> sublayout) where
300+ => HasForeign lang (IsSecure :> sublayout) where
287 type Foreign (IsSecure :> sublayout) = Foreign sublayout
301 type Foreign (IsSecure :> sublayout) = Foreign sublayout
288
302
289 foreignFor lang Proxy req =
303 foreignFor lang Proxy req =
@@ -302,7 +316,8 @@ instance HasForeign lang sublayout =>
302
316
303 foreignFor lang Proxy = foreignFor lang (Proxy :: Proxy sublayout)
317 foreignFor lang Proxy = foreignFor lang (Proxy :: Proxy sublayout)
304
318
319+instance HasForeign lang sublayout
305−instance HasForeign lang sublayout => HasForeign lang (HttpVersion :> sublayout) where
320+ => HasForeign lang (HttpVersion :> sublayout) where
306 type Foreign (HttpVersion :> sublayout) = Foreign sublayout
321 type Foreign (HttpVersion :> sublayout) = Foreign sublayout
307
322
308 foreignFor lang Proxy req =
323 foreignFor lang Proxy req =
@@ -317,10 +332,15 @@ class GenerateList reqs where
317instance GenerateList Req where
332instance GenerateList Req where
318 generateList r = [r]
333 generateList r = [r]
319
334
320−instance (GenerateList start, GenerateList rest) => GenerateList (start :<|> rest) where
335+instance (GenerateList start, GenerateList rest)
336+ => GenerateList (start :<|> rest) where
321 generateList (start :<|> rest) = (generateList start) ++ (generateList rest)
337 generateList (start :<|> rest) = (generateList start) ++ (generateList rest)
322
338
323-- | Generate the necessary data for codegen as a list, each 'Req'
339-- | Generate the necessary data for codegen as a list, each 'Req'
324-- describing one endpoint from your API type.
340-- describing one endpoint from your API type.
341+listFromAPI
325−listFromAPI :: (HasForeign lang api, GenerateList (Foreign api)) => Proxy lang -> Proxy api -> [Req]
342+ :: (HasForeign lang api, GenerateList (Foreign api))
343+ => Proxy lang
344+ -> Proxy api
345+ -> [Req]
326listFromAPI lang p = generateList (foreignFor lang p defReq)
346listFromAPI lang p = generateList (foreignFor lang p defReq)
servant-foreign/test/Servant/ForeignSpec.hs+63−61
@@ -15,7 +15,6 @@ module Servant.ForeignSpec where
15import Data.Monoid ((<>))
15import Data.Monoid ((<>))
16import Data.Proxy
16import Data.Proxy
17import Servant.Foreign
17import Servant.Foreign
18−import Servant.Foreign.Internal
19
18
20import Test.Hspec
19import Test.Hspec
21
20
@@ -35,15 +34,19 @@ camelCaseSpec = describe "camelCase" $ do
35data LangX
34data LangX
36
35
37instance HasForeignType LangX () where
36instance HasForeignType LangX () where
38− typeFor _ _ = "voidX"
37+ typeFor _ _ = "voidX"
38+
39instance HasForeignType LangX Int where
39instance HasForeignType LangX Int where
40− typeFor _ _ = "intX"
40+ typeFor _ _ = "intX"
41+
41instance HasForeignType LangX Bool where
42instance HasForeignType LangX Bool where
42− typeFor _ _ = "boolX"
43+ typeFor _ _ = "boolX"
44+
43instance OVERLAPPING_ HasForeignType LangX String where
45instance OVERLAPPING_ HasForeignType LangX String where
44− typeFor _ _ = "stringX"
46+ typeFor _ _ = "stringX"
47+
45instance OVERLAPPABLE_ HasForeignType LangX a => HasForeignType LangX [a] where
48instance OVERLAPPABLE_ HasForeignType LangX a => HasForeignType LangX [a] where
46− typeFor lang _ = "listX of " <> typeFor lang (Proxy :: Proxy a)
49+ typeFor lang _ = "listX of " <> typeFor lang (Proxy :: Proxy a)
47
50
48type TestApi
51type TestApi
49 = "test" :> Header "header" [String] :> QueryFlag "flag" :> Get '[JSON] Int
52 = "test" :> Header "header" [String] :> QueryFlag "flag" :> Get '[JSON] Int
@@ -56,58 +59,57 @@ testApi = listFromAPI (Proxy :: Proxy LangX) (Proxy :: Proxy TestApi)
56
59
57listFromAPISpec :: Spec
60listFromAPISpec :: Spec
58listFromAPISpec = describe "listFromAPI" $ do
61listFromAPISpec = describe "listFromAPI" $ do
59− it "generates 4 endpoints for TestApi" $ do
62+ it "generates 4 endpoints for TestApi" $ do
60− length testApi `shouldBe` 4
63+ length testApi `shouldBe` 4
61−
64+
62− let [getReq, postReq, putReq, deleteReq] = testApi
65+ let [getReq, postReq, putReq, deleteReq] = testApi
63−
66+
64− it "collects all info for get request" $ do
67+ it "collects all info for get request" $ do
65− shouldBe getReq $ defReq
68+ shouldBe getReq $ defReq
66− { _reqUrl = Url
69+ { _reqUrl = Url
67− [ Segment $ Static "test" ]
70+ [ Segment $ Static "test" ]
68− [ QueryArg ("flag", "boolX") Flag ]
71+ [ QueryArg ("flag", "boolX") Flag ]
69− , _reqMethod = "GET"
72+ , _reqMethod = "GET"
70− , _reqHeaders = [HeaderArg ("header", "listX of stringX")]
73+ , _reqHeaders = [HeaderArg ("header", "listX of stringX")]
71− , _reqBody = Nothing
74+ , _reqBody = Nothing
72− , _reqReturnType = "intX"
75+ , _reqReturnType = "intX"
73− , _funcName = ["get", "test"]
76+ , _reqFuncName = ["get", "test"]
74− }
77+ }
75−
78+
76− it "collects all info for post request" $ do
79+ it "collects all info for post request" $ do
77− shouldBe postReq $ defReq
80+ shouldBe postReq $ defReq
78− { _reqUrl = Url
81+ { _reqUrl = Url
79− [ Segment $ Static "test" ]
82+ [ Segment $ Static "test" ]
80− [ QueryArg ("param", "intX") Normal ]
83+ [ QueryArg ("param", "intX") Normal ]
81− , _reqMethod = "POST"
84+ , _reqMethod = "POST"
82− , _reqHeaders = []
85+ , _reqHeaders = []
83− , _reqBody = Just "listX of stringX"
86+ , _reqBody = Just "listX of stringX"
84− , _reqReturnType = "voidX"
87+ , _reqReturnType = "voidX"
85− , _funcName = ["post", "test"]
88+ , _reqFuncName = ["post", "test"]
86− }
89+ }
87−
90+
88− it "collects all info for put request" $ do
91+ it "collects all info for put request" $ do
89− shouldBe putReq $ defReq
92+ shouldBe putReq $ defReq
90− { _reqUrl = Url
93+ { _reqUrl = Url
91− [ Segment $ Static "test" ]
94+ [ Segment $ Static "test" ]
92− -- Shoud this be |intX| or |listX of intX| ?
95+ -- Shoud this be |intX| or |listX of intX| ?
93− [ QueryArg ("params", "listX of intX") List ]
96+ [ QueryArg ("params", "listX of intX") List ]
94− , _reqMethod = "PUT"
97+ , _reqMethod = "PUT"
95− , _reqHeaders = []
98+ , _reqHeaders = []
96− , _reqBody = Just "stringX"
99+ , _reqBody = Just "stringX"
97− , _reqReturnType = "voidX"
100+ , _reqReturnType = "voidX"
98− , _funcName = ["put", "test"]
101+ , _reqFuncName = ["put", "test"]
99− }
102+ }
100−
103+
101− it "collects all info for delete request" $ do
104+ it "collects all info for delete request" $ do
102− shouldBe deleteReq $ defReq
105+ shouldBe deleteReq $ defReq
103− { _reqUrl = Url
106+ { _reqUrl = Url
104− [ Segment $ Static "test"
107+ [ Segment $ Static "test"
105− , Segment $ Cap ("id", "intX") ]
108+ , Segment $ Cap ("id", "intX") ]
106− []
109+ []
107− , _reqMethod = "DELETE"
110+ , _reqMethod = "DELETE"
108− , _reqHeaders = []
111+ , _reqHeaders = []
109− , _reqBody = Nothing
112+ , _reqBody = Nothing
110− , _reqReturnType = "voidX"
113+ , _reqReturnType = "voidX"
111− , _funcName = ["delete", "test", "by", "id"]
114+ , _reqFuncName = ["delete", "test", "by", "id"]
112− }
115+ }
113−
servant-js/src/Servant/JS/Angular.hs+1−1
@@ -128,7 +128,7 @@ generateAngularJSWith ngOptions opts req = "\n" <>
128
128
129 fsep = if hasService then ":" else " ="
129 fsep = if hasService then ":" else " ="
130
130
131− fname = namespace <> (functionNameBuilder opts $ req ^. funcName)
131+ fname = namespace <> (functionNameBuilder opts $ req ^. reqFuncName)
132
132
133 method = req ^. reqMethod
133 method = req ^. reqMethod
134 url = if url' == "'" then "'/'" else url'
134 url = if url' == "'" then "'/'" else url'
servant-js/src/Servant/JS/Axios.hs+1−1
@@ -116,7 +116,7 @@ generateAxiosJSWith aopts opts req = "\n" <>
116 where
116 where
117 hasNoModule = moduleName opts == ""
117 hasNoModule = moduleName opts == ""
118
118
119− fname = namespace <> (functionNameBuilder opts $ req ^. funcName)
119+ fname = namespace <> (functionNameBuilder opts $ req ^. reqFuncName)
120
120
121 method = T.toLower . decodeUtf8 $ req ^. reqMethod
121 method = T.toLower . decodeUtf8 $ req ^. reqMethod
122 url = if url' == "'" then "'/'" else url'
122 url = if url' == "'" then "'/'" else url'
servant-js/src/Servant/JS/Internal.hs+13−6
@@ -51,12 +51,19 @@ type JavaScriptGenerator = [Req] -> Text
51-- customize the output
51-- customize the output
52data CommonGeneratorOptions = CommonGeneratorOptions
52data CommonGeneratorOptions = CommonGeneratorOptions
53 {
53 {
54− functionNameBuilder :: FunctionName -> Text -- ^ function generating function names
54+ functionNameBuilder :: FunctionName -> Text
55+ -- ^ function generating function names
56+ , requestBody :: Text
55− , requestBody :: Text -- ^ name used when a user want to send the request body (to let you redefine it)
57+ -- ^ name used when a user want to send the request body
58+ -- (to let you redefine it)
59+ , successCallback :: Text
56− , successCallback :: Text -- ^ name of the callback parameter when the request was successful
60+ -- ^ name of the callback parameter when the request was successful
61+ , errorCallback :: Text
57− , errorCallback :: Text -- ^ name of the callback parameter when the request reported an error
62+ -- ^ name of the callback parameter when the request reported an error
63+ , moduleName :: Text
58− , moduleName :: Text -- ^ namespace on which we define the foreign function (empty mean local var)
64+ -- ^ namespace on which we define the foreign function (empty mean local var)
65+ , urlPrefix :: Text
59− , urlPrefix :: Text -- ^ a prefix we should add to the Url in the codegen
66+ -- ^ a prefix we should add to the Url in the codegen
60 }
67 }
61
68
62-- | Default options.
69-- | Default options.
servant-js/src/Servant/JS/JQuery.hs+1−1
@@ -81,7 +81,7 @@ generateJQueryJSWith opts req = "\n" <>
81 namespace = if (moduleName opts) == ""
81 namespace = if (moduleName opts) == ""
82 then "var "
82 then "var "
83 else (moduleName opts) <> "."
83 else (moduleName opts) <> "."
84− fname = namespace <> (functionNameBuilder opts $ req ^. funcName)
84+ fname = namespace <> (functionNameBuilder opts $ req ^. reqFuncName)
85
85
86 method = req ^. reqMethod
86 method = req ^. reqMethod
87 url = if url' == "'" then "'/'" else url'
87 url = if url' == "'" then "'/'" else url'
servant-js/src/Servant/JS/Vanilla.hs+1−1
@@ -93,7 +93,7 @@ generateVanillaJSWith opts req = "\n" <>
93 namespace = if moduleName opts == ""
93 namespace = if moduleName opts == ""
94 then "var "
94 then "var "
95 else (moduleName opts) <> "."
95 else (moduleName opts) <> "."
96− fname = namespace <> (functionNameBuilder opts $ req ^. funcName)
96+ fname = namespace <> (functionNameBuilder opts $ req ^. reqFuncName)
97
97
98 method = req ^. reqMethod
98 method = req ^. reqMethod
99 url = if url' == "'" then "'/'" else url'
99 url = if url' == "'" then "'/'" else url'