152 lines
5.1 KiB
Haskell
152 lines
5.1 KiB
Haskell
{-# LANGUAGE DataKinds #-}
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
{-# LANGUAGE FlexibleInstances #-}
|
|
{-# LANGUAGE TypeOperators #-}
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
-----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : Servant.JS
|
|
-- License : BSD3
|
|
-- Maintainer : Alp Mestanogullari <alpmestan@gmail.com>
|
|
-- Stability : experimental
|
|
-- Portability : non-portable
|
|
--
|
|
-- Generating Javascript code to query your APIs using vanilla Javascript,
|
|
-- Angular.js or JQuery.
|
|
--
|
|
-- Using this package is very simple. Say you have this API type around:
|
|
--
|
|
-- > type API = "users" :> Get '[JSON] [Users]
|
|
-- > :<|> "messages" :> Get '[JSON] [Message]
|
|
--
|
|
-- All you need to do to generate the Javascript code is to write a 'Proxy'
|
|
-- for this API type:
|
|
--
|
|
-- > api :: Proxy API
|
|
-- > api = Proxy
|
|
--
|
|
-- And pick one of the generators:
|
|
--
|
|
-- - 'vanillaJS' and 'vanillaJSWith' generate functions that use
|
|
-- /XMLHttpRequest/ to query your endpoints. The former just calls
|
|
-- the latter with default code-generation options.
|
|
-- - 'jquery' and 'jqueryWith' follow the same pattern except that they
|
|
-- generate functions that use /jQuery/'s AJAX functions.
|
|
-- - 'angular' and 'angularWith' do the same but use /Angular.js/'s $http
|
|
-- service. In addition, we provide 'angularService' and 'angularServiceWith'
|
|
-- which produce functions under an Angular service that your controlers
|
|
-- can depend on to query the API.
|
|
--
|
|
-- Let's keep it simple and produce vanilla Javascript code with the default options.
|
|
--
|
|
-- @
|
|
-- jsCode :: Text
|
|
-- jsCode = 'jsForAPI' api 'vanillaJS'
|
|
-- @
|
|
--
|
|
-- That's it! If you want to write that code to a file:
|
|
--
|
|
-- @
|
|
-- writeJSCode :: IO ()
|
|
-- writeJSCode = 'writeJSForAPI' api 'vanillaJS' "./my_api.js"
|
|
-- @
|
|
--
|
|
-- If you want to customize the rendering options, take a look
|
|
-- at 'CommonGeneratorOptions' which are generic options common to all the
|
|
-- generators. the /xxxWith/ variants all take 'CommonGeneratorOptions' whereas
|
|
-- the /xxx/ versions use 'defCommonGeneratorOptions'. Once you have some custom
|
|
--
|
|
-- > myOptions :: 'CommonGeneratorOptions'
|
|
--
|
|
-- All you need to do to use it is to use 'vanillaJSWith' and pass it @myOptions@.
|
|
--
|
|
-- @
|
|
-- jsCodeWithMyOptions :: Text
|
|
-- jsCodeWithMyOptions = 'jsForAPI' api ('vanillaJSWith' myOptions)
|
|
-- @
|
|
--
|
|
-- Follow the same pattern for any other generator.
|
|
--
|
|
-- /Note/: The Angular generators take an additional type of options,
|
|
-- namely 'AngularOptions', to let you tweak aspects of the code generation
|
|
-- that are specific to /Angular.js/.
|
|
module Servant.JS
|
|
( -- * Generating javascript code from an API type
|
|
jsForAPI
|
|
, writeJSForAPI
|
|
, JavaScriptGenerator
|
|
|
|
, -- * Options common to all generators
|
|
CommonGeneratorOptions(..)
|
|
, defCommonGeneratorOptions
|
|
|
|
, -- * Function renamers
|
|
concatCase
|
|
, snakeCase
|
|
, camelCase
|
|
|
|
, -- * Vanilla Javascript code generation
|
|
vanillaJS
|
|
, vanillaJSWith
|
|
|
|
, -- * JQuery code generation
|
|
jquery
|
|
, jqueryWith
|
|
|
|
, -- * Angular.js code generation
|
|
angular
|
|
, angularWith
|
|
, angularService
|
|
, angularServiceWith
|
|
, AngularOptions(..)
|
|
, defAngularOptions
|
|
|
|
, -- * Axios code generation
|
|
axios
|
|
, axiosWith
|
|
, AxiosOptions(..)
|
|
, defAxiosOptions
|
|
|
|
, -- * Misc.
|
|
listFromAPI
|
|
, javascript
|
|
, NoTypes
|
|
, GenerateList(..)
|
|
) where
|
|
|
|
import Prelude hiding (writeFile)
|
|
import Data.Proxy
|
|
import Data.Text
|
|
import Data.Text.IO (writeFile)
|
|
import Servant.JS.Angular
|
|
import Servant.JS.Axios
|
|
import Servant.JS.Internal
|
|
import Servant.JS.JQuery
|
|
import Servant.JS.Vanilla
|
|
import Servant.Foreign (GenerateList(..), listFromAPI, NoTypes)
|
|
|
|
-- | Generate the data necessary to generate javascript code
|
|
-- for all the endpoints of an API, as ':<|>'-separated values
|
|
-- of type 'AjaxReq'.
|
|
javascript :: HasForeign NoTypes layout => Proxy layout -> Foreign layout
|
|
javascript p = foreignFor (Proxy :: Proxy NoTypes) p defReq
|
|
|
|
-- | Directly generate all the javascript functions for your API
|
|
-- from a 'Proxy' for your API type. You can then write it to
|
|
-- a file or integrate it in a page, for example.
|
|
jsForAPI :: (HasForeign NoTypes api, GenerateList (Foreign api))
|
|
=> Proxy api -- ^ proxy for your API type
|
|
-> JavaScriptGenerator -- ^ js code generator to use (angular, vanilla js, jquery, others)
|
|
-> Text -- ^ a text that you can embed in your pages or write to a file
|
|
jsForAPI p gen = gen (listFromAPI (Proxy :: Proxy NoTypes) p)
|
|
|
|
-- | Directly generate all the javascript functions for your API
|
|
-- from a 'Proxy' for your API type using the given generator
|
|
-- and write the resulting code to a file at the given path.
|
|
writeJSForAPI :: (HasForeign NoTypes api, GenerateList (Foreign api))
|
|
=> Proxy api -- ^ proxy for your API type
|
|
-> JavaScriptGenerator -- ^ js code generator to use (angular, vanilla js, jquery, others)
|
|
-> FilePath -- ^ path to the file you want to write the resulting javascript code into
|
|
-> IO ()
|
|
writeJSForAPI p gen fp = writeFile fp (jsForAPI p gen)
|
|
|