@@ -4,56 +4,140 @@
4{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
5-----------------------------------------------------------------------------
5-----------------------------------------------------------------------------
7−-- Module : Servant.JQuery
7+-- Module : Servant.JS
8-- License : BSD3
8-- License : BSD3
9-- Maintainer : Alp Mestanogullari <alpmestan@gmail.com>
9-- Maintainer : Alp Mestanogullari <alpmestan@gmail.com>
10-- Stability : experimental
10-- Stability : experimental
11-- Portability : non-portable
11-- Portability : non-portable
13+-- Generating Javascript code to query your APIs using vanilla Javascript,
14+-- Angular.js or JQuery.
16+-- Using this package is very simple. Say you have this API type around:
18+-- > type API = "users" :> Get '[JSON] [Users]
19+-- > :<|> "messages" :> Get '[JSON] [Message]
21+-- All you need to do to generate the Javascript code is to write a 'Proxy'
27+-- And pick one of the generators:
29+-- - 'vanillaJS' and 'vanillaJSWith' generate functions that use
30+-- /XMLHttpRequest/ to query your endpoints. The former just calls
31+-- the latter with default code-generation options.
32+-- - 'jquery' and 'jqueryWith' follow the same pattern except that they
33+-- generate functions that use /jQuery/'s AJAX functions.
34+-- - 'angular' and 'angularWith' do the same but use /Angular.js/'s $http
35+-- service. In addition, we provide 'angularService' and 'angularServiceWith'
36+-- which produce functions under an Angular service that your controlers
37+-- can depend on to query the API.
39+-- Let's keep it simple and produce vanilla Javascript code with the default options.
43+-- jsCode = 'jsForAPI' api 'vanillaJS'
46+-- That's it! If you want to write that code to a file:
49+-- writeJSCode :: IO ()
50+-- writeJSCode = 'writeJSForAPI' api 'vanillaJS' "./my_api.js"
53+-- If you want to customize the rendering options, take a look
54+-- at 'CommonGeneratorOptions' which are generic options common to all the
55+-- generators. the /xxxWith/ variants all take 'CommonGeneratorOptions' whereas
56+-- the /xxx/ versions use 'defCommonGeneratorOptions'. Once you have some custom
58+-- > myOptions :: 'CommonGeneratorOptions'
60+-- All you need to do to use it is to use 'vanillaJSWith' and pass it @myOptions@.
63+-- jsCodeWithMyOptions :: String
64+-- jsCodeWithMyOptions = 'jsForAPI' api ('vanillaJSWith' myOptions)
67+-- Follow the same pattern for any other generator.
69+-- /Note/: The Angular generators take an additional type of options,
70+-- namely 'AngularOptions', to let you tweak aspects of the code generation
71+-- that are specific to /Angular.js/.
12module Servant.JS
72module Servant.JS
13− ( javascript
73+ ( -- * Generating javascript code from an API type
15− , jsForAPI
74+ jsForAPI
76+ , JavaScriptGenerator
78+ , -- * Options common to all generators
79+ CommonGeneratorOptions(..)
80+ , defCommonGeneratorOptions
82+ , -- * Vanilla Javascript code generation
86+ , -- * JQuery code generation
90+ , -- * Angular.js code generation
16− , listFromAPI
99+ listFromAPI
17− , printJS
100+ , javascript
18− , module Servant.JS.Internal
101+ , HasJS(..)
19− , GenerateCode(..)
102+ , GenerateList(..)
20− , CommonGeneratorOptions(..)
103+ , AjaxReq
23import Data.Proxy
106import Data.Proxy
24import Servant.API
107import Servant.API
108+import Servant.JS.Angular
25import Servant.JS.Internal
109import Servant.JS.Internal
110+import Servant.JS.JQuery
111+import Servant.JS.Vanilla
113+-- | Generate the data necessary to generate javascript code
114+-- for all the endpoints of an API, as ':<|>'-separated values
115+-- of type 'AjaxReq'.
27javascript :: HasJS layout => Proxy layout -> JS layout
116javascript :: HasJS layout => Proxy layout -> JS layout
28javascript p = javascriptFor p defReq
117javascript p = javascriptFor p defReq
30−printJS :: AjaxReq -> JavaScriptGenerator -> IO ()
31−printJS req gen = putStrLn (generateJS req gen)
33−generateJS :: AjaxReq -> JavaScriptGenerator -> String
34−generateJS req gen = gen $ req
36−-- | Utility class used by 'jsForAPI' which will
37−-- directly hand you all the Javascript code
38−-- instead of handing you a ':<|>'-separated list
39−-- of 'AjaxReq' like 'javascript' and then having to
40−-- use 'generateJS' on each 'AjaxReq'.
41−class GenerateCode reqs where
42− jsFor :: reqs -> JavaScriptGenerator -> String
44−instance GenerateCode AjaxReq where
47−instance GenerateCode rest => GenerateCode (AjaxReq :<|> rest) where
48− jsFor (req :<|> rest) gen = jsFor req gen ++ jsFor rest gen
50-- | Directly generate all the javascript functions for your API
119-- | Directly generate all the javascript functions for your API
51-- from a 'Proxy' for your API type. You can then write it to
120-- from a 'Proxy' for your API type. You can then write it to
52-- a file or integrate it in a page, for example.
121-- a file or integrate it in a page, for example.
53−jsForAPI :: (HasJS api, GenerateCode (JS api)) => Proxy api
122+jsForAPI :: (HasJS api, GenerateList (JS api))
123+ => Proxy api -- ^ proxy for your API type
54− -> JavaScriptGenerator -> String
124+ -> JavaScriptGenerator -- ^ js code generator to use (angular, vanilla js, jquery, others)
55−jsForAPI p = jsFor (javascript p)
125+ -> String -- ^ a string that you can embed in your pages or write to a file
126+jsForAPI p gen = gen (listFromAPI p)
128+-- | Directly generate all the javascript functions for your API
129+-- from a 'Proxy' for your API type using the given generator
130+-- and write the resulting code to a file at the given path.
131+writeJSForAPI :: (HasJS api, GenerateList (JS api))
132+ => Proxy api -- ^ proxy for your API type
133+ -> JavaScriptGenerator -- ^ js code generator to use (angular, vanilla js, jquery, others)
134+ -> FilePath -- ^ path to the file you want to write the resulting javascript code into
136+writeJSForAPI p gen fp = writeFile fp (jsForAPI p gen)
138+-- | Utility class used by 'jsForAPI' which computes
139+-- the data needed to generate a function for each endpoint
140+-- and hands it all back in a list.
57class GenerateList reqs where
141class GenerateList reqs where
58 generateList :: reqs -> [AjaxReq]
142 generateList :: reqs -> [AjaxReq]
@@ -63,5 +147,7 @@ instance GenerateList AjaxReq where
63instance GenerateList rest => GenerateList (AjaxReq :<|> rest) where
147instance GenerateList rest => GenerateList (AjaxReq :<|> rest) where
64 generateList (r :<|> rest) = r : generateList rest
148 generateList (r :<|> rest) = r : generateList rest
150+-- | Generate the necessary data for JS codegen as a list, each 'AjaxReq'
151+-- describing one endpoint from your API type.
66listFromAPI :: (HasJS api, GenerateList (JS api)) => Proxy api -> [AjaxReq]
152listFromAPI :: (HasJS api, GenerateList (JS api)) => Proxy api -> [AjaxReq]
67listFromAPI p = generateList (javascript p)
153listFromAPI p = generateList (javascript p)