Shpadoinkle-router-0.2.0.1: Shpadoinkle/Router/Client.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
{-# OPTIONS_GHC -Wno-type-defaults #-}
-- | Helper for querying the server from client side code using a derived client.
-- This module exists to save you from having to use CPP yourself.
module Shpadoinkle.Router.Client
( runXHR
, runXHR'
, module Servant.Client.JS
) where
import Control.Monad.Catch (MonadThrow (throwM))
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import GHCJS.DOM.Types (JSM)
import Language.Javascript.JSaddle (FromJSVal (fromJSVal), jsg, (!))
import Servant.Client.JS (BaseUrl (..), ClientEnv (..),
ClientError (..), ClientM (..),
EmptyClient (..), HasClient (..),
InvalidBaseUrlException, Response,
ResponseF (..), Scheme (..),
StreamingResponse, client,
parseBaseUrl, runClientM,
showBaseUrl,
withStreamingRequestJSM)
import Text.Read (readMaybe)
import UnliftIO (MonadIO (liftIO))
default (Text)
-- | Run the ClientM from Servant as an XHR request.
runXHR :: ClientM a -> JSM a
runXHR m = do -- TODO cache the base url or make it optional
loc <- jsg ("window" :: Text) >>= (! ("location" :: Text))
protocol <- mapProtocol <$> (loc ! ("protocol" :: Text) >>= fromJSVal)
hostname <- fromMaybe "localhost" <$> (loc ! ("hostname" :: Text) >>= fromJSVal)
port <- fromMaybe (defaultPort protocol) . (readMaybe =<<) <$> (loc ! ("port" :: Text) >>= fromJSVal)
runXHR' m . ClientEnv $ BaseUrl protocol hostname port ""
where mapProtocol :: Maybe String -> Scheme
mapProtocol (Just "https:") = Https
mapProtocol _ = Http
defaultPort :: Scheme -> Int
defaultPort Https = 443
defaultPort Http = 80
-- | Run the ClientM from Servant as an XHR request with a customized base URL.
runXHR' :: ClientM a -> ClientEnv -> JSM a
runXHR' m env = either (liftIO . throwM) pure =<< runClientM m env