servant/servant-js/src/Servant/JS/Axios.hs

133 lines
4.1 KiB
Haskell
Raw Normal View History

2015-10-02 13:59:54 +02:00
{-#LANGUAGE OverloadedStrings #-}
2015-07-27 16:29:08 +02:00
module Servant.JS.Axios where
import Control.Lens
import Data.Maybe (isJust)
import Data.Monoid
2015-10-02 13:59:54 +02:00
import Data.Text (Text)
import qualified Data.Text as T
import Servant.Foreign
import Servant.JS.Internal
2015-07-27 16:29:08 +02:00
2015-07-28 15:06:00 +02:00
-- | Axios 'configuration' type
-- Let you customize the generation using Axios capabilities
data AxiosOptions = AxiosOptions
{ -- | indicates whether or not cross-site Access-Control requests
-- should be made using credentials
withCredentials :: !Bool
-- | the name of the cookie to use as a value for xsrf token
2015-10-02 13:59:54 +02:00
, xsrfCookieName :: !(Maybe Text)
2015-07-28 15:06:00 +02:00
-- | the name of the header to use as a value for xsrf token
2015-10-02 13:59:54 +02:00
, xsrfHeaderName :: !(Maybe Text)
2015-07-28 15:06:00 +02:00
}
-- | Default instance of the AxiosOptions
-- Defines the settings as they are in the Axios documentation
-- by default
defAxiosOptions :: AxiosOptions
defAxiosOptions = AxiosOptions
{ withCredentials = False
, xsrfCookieName = Nothing
, xsrfHeaderName = Nothing
}
2015-07-27 16:29:08 +02:00
-- | Generate regular javacript functions that use
-- the axios library, using default values for 'CommonGeneratorOptions'.
2015-07-28 15:06:00 +02:00
axios :: AxiosOptions -> JavaScriptGenerator
axios aopts = axiosWith aopts defCommonGeneratorOptions
2015-07-27 16:29:08 +02:00
-- | Generate regular javascript functions that use the axios library.
2015-07-28 15:06:00 +02:00
axiosWith :: AxiosOptions -> CommonGeneratorOptions -> JavaScriptGenerator
2015-10-02 13:59:54 +02:00
axiosWith aopts opts = T.intercalate "\n\n" . map (generateAxiosJSWith aopts opts)
2015-07-27 16:29:08 +02:00
-- | js codegen using axios library using default options
2015-10-02 13:59:54 +02:00
generateAxiosJS :: AxiosOptions -> AjaxReq -> Text
2015-07-28 15:06:00 +02:00
generateAxiosJS aopts = generateAxiosJSWith aopts defCommonGeneratorOptions
2015-07-27 16:29:08 +02:00
-- | js codegen using axios library
2015-10-02 13:59:54 +02:00
generateAxiosJSWith :: AxiosOptions -> CommonGeneratorOptions -> AjaxReq -> Text
2015-07-28 15:06:00 +02:00
generateAxiosJSWith aopts opts req = "\n" <>
2015-07-27 16:29:08 +02:00
fname <> " = function(" <> argsStr <> ")\n"
<> "{\n"
2015-07-28 01:25:00 +02:00
<> " return axios({ url: " <> url <> "\n"
<> " , method: '" <> method <> "'\n"
2015-07-27 16:29:08 +02:00
<> dataBody
<> reqheaders
2015-07-28 15:06:00 +02:00
<> withCreds
<> xsrfCookie
<> xsrfHeader
2015-07-27 16:29:08 +02:00
<> " });\n"
<> "}\n"
2015-10-02 13:59:54 +02:00
where argsStr = T.intercalate ", " args
2015-07-27 16:29:08 +02:00
args = captures
++ map (view $ argName._1) queryparams
2015-07-27 16:29:08 +02:00
++ body
++ map (toValidFunctionName . (<>) "header" . fst . headerArg) hs
captures = map (fst . captureArg)
2015-07-27 16:29:08 +02:00
. filter isCapture
$ req ^. reqUrl.path
hs = req ^. reqHeaders
queryparams = req ^.. reqUrl.queryStr.traverse
body = if isJust (req ^. reqBody)
2015-07-27 16:29:08 +02:00
then [requestBody opts]
else []
dataBody =
if isJust (req ^. reqBody)
2015-07-28 11:33:36 +02:00
then " , data: body\n" <>
2015-07-27 16:29:08 +02:00
" , responseType: 'json'\n"
else ""
2015-07-28 15:06:00 +02:00
withCreds =
if withCredentials aopts
then " , withCredentials: true\n"
else ""
xsrfCookie =
2015-07-28 15:06:00 +02:00
case xsrfCookieName aopts of
Just name -> " , xsrfCookieName: '" <> name <> "'\n"
Nothing -> ""
xsrfHeader =
case xsrfHeaderName aopts of
Just name -> " , xsrfHeaderName: '" <> name <> "'\n"
Nothing -> ""
2015-07-27 16:29:08 +02:00
reqheaders =
if null hs
then ""
2015-07-28 15:06:00 +02:00
else " , headers: { " <> headersStr <> " }\n"
2015-07-27 16:29:08 +02:00
2015-10-02 13:59:54 +02:00
where headersStr = T.intercalate ", " $ map headerStr hs
headerStr header = "\"" <>
fst (headerArg header) <>
2015-10-02 13:59:54 +02:00
"\": " <> toJSHeader header
2015-07-27 16:29:08 +02:00
namespace =
if hasNoModule
then "var "
else (moduleName opts) <> "."
where
2015-10-02 13:59:54 +02:00
hasNoModule = moduleName opts == ""
fname = namespace <> (functionNameBuilder opts $ req ^. funcName)
2015-10-02 13:59:54 +02:00
method = T.toLower $ req ^. reqMethod
2015-07-27 16:29:08 +02:00
url = if url' == "'" then "'/'" else url'
url' = "'"
2015-10-02 13:59:54 +02:00
<> urlPrefix opts
<> urlArgs
<> queryArgs
2015-07-27 16:29:08 +02:00
urlArgs = jsSegments
$ req ^.. reqUrl.path.traverse
queryArgs = if null queryparams
then ""
2015-10-02 13:59:54 +02:00
else " + '?" <> jsParams queryparams