diff --git a/server/src-exec/Main.hs b/server/src-exec/Main.hs index 480cfd26..4f69bfd6 100644 --- a/server/src-exec/Main.hs +++ b/server/src-exec/Main.hs @@ -33,13 +33,14 @@ data RavenOptions data ServeOptions = ServeOptions - { soPort :: !Int - , soConnParams :: !Q.ConnParams - , soTxIso :: !Q.TxIsolation - , soRootDir :: !(Maybe String) - , soAccessKey :: !(Maybe AccessKey) - , soCorsConfig :: !CorsConfig - , soWebHook :: !(Maybe T.Text) + { soPort :: !Int + , soConnParams :: !Q.ConnParams + , soTxIso :: !Q.TxIsolation + , soRootDir :: !(Maybe String) + , soAccessKey :: !(Maybe AccessKey) + , soCorsConfig :: !CorsConfig + , soWebHook :: !(Maybe T.Text) + , soEnableConsole :: !Bool } deriving (Show, Eq) data RavenMode @@ -70,6 +71,7 @@ parseRavenMode = subparser <*> parseAccessKey <*> parseCorsConfig <*> parseWebHook + <*> parseEnableConsole parseArgs :: IO RavenOptions parseArgs = execParser opts @@ -101,7 +103,7 @@ main = withStdoutLogger ravenLogGen $ \rlogger -> do return $ mkConnInfo rci printConnInfo ci case ravenMode of - ROServe (ServeOptions port cp isoL mRootDir mAccessKey corsCfg mWebHook) -> do + ROServe (ServeOptions port cp isoL mRootDir mAccessKey corsCfg mWebHook enableConsole) -> do am <- either ((>> exitFailure) . putStrLn) return $ mkAuthMode mAccessKey mWebHook initialise ci @@ -109,7 +111,7 @@ main = withStdoutLogger ravenLogGen $ \rlogger -> do pool <- Q.initPGPool ci cp runSpockNoBanner port $ do putStrLn $ "server: running on port " ++ show port - spockT id $ app isoL mRootDir rlogger pool am corsCfg + spockT id $ app isoL mRootDir rlogger pool am corsCfg enableConsole ROExport -> do res <- runTx ci fetchMetadata either ((>> exitFailure) . printJSON) printJSON res diff --git a/server/src-lib/Hasura/Server/App.hs b/server/src-lib/Hasura/Server/App.hs index 46f49ecf..cf364d19 100644 --- a/server/src-lib/Hasura/Server/App.hs +++ b/server/src-lib/Hasura/Server/App.hs @@ -1,13 +1,14 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell #-} module Hasura.Server.App where import Control.Concurrent.MVar -import Control.Lens +import Control.Lens hiding ((.=)) import Data.Char (isSpace) import Data.IORef @@ -15,7 +16,6 @@ import Crypto.Hash (Digest, SHA1, hash) import Data.Aeson hiding (json) import qualified Data.ByteString.Lazy as BL import Data.CaseInsensitive (CI (..), original) -import qualified Data.FileEmbed as FE import qualified Data.HashMap.Strict as M import qualified Data.String.Conversions as CS import qualified Data.Text as T @@ -28,6 +28,7 @@ import qualified Network.HTTP.Client.TLS as HT import Network.Wai (strictRequestBody) import qualified Network.Wreq as Wq import qualified Network.Wreq.Types as WqT +import qualified Data.FileEmbed as FE import Web.Spock.Core @@ -37,28 +38,28 @@ import qualified Network.Wai.Middleware.Static as MS import qualified Data.Text.Encoding.Error as TE import qualified Database.PG.Query as Q -import qualified Hasura.GraphQL.Execute as GE -import qualified Hasura.GraphQL.Execute.Result as GE -import qualified Hasura.GraphQL.Schema as GS +import qualified Hasura.GraphQL.Execute as GE +import qualified Hasura.GraphQL.Execute.Result as GE +import qualified Hasura.GraphQL.Schema as GS +import Hasura.Prelude hiding (get, put) import Hasura.RQL.DDL.Schema.Table import Hasura.RQL.DML.Explain import Hasura.RQL.DML.QueryTemplate import Hasura.RQL.Types import Hasura.Server.Init import Hasura.Server.Logging -import Hasura.Prelude hiding (get, put) -import Hasura.Server.Middleware (corsMiddleware, +import Hasura.Server.Middleware (corsMiddleware, mkDefaultCorsPolicy) import Hasura.Server.Query import Hasura.Server.Utils import Hasura.SQL.Types -landingPage :: String -landingPage = $(FE.embedStringFile "src-rsr/landing_page.html") - type RavenLogger = ServerLogger (BL.ByteString, Either QErr BL.ByteString) +consoleHTML :: T.Text +consoleHTML = $(FE.embedStringFile "src-rsr/console.html") + ravenLogGen :: LogDetailG (BL.ByteString, Either QErr BL.ByteString) ravenLogGen _ (reqBody, res) = @@ -361,8 +362,9 @@ app -> Q.PGPool -> AuthMode -> CorsConfig + -> Bool -> SpockT IO () -app isoLevel mRootDir logger pool mode corsCfg = do +app isoLevel mRootDir logger pool mode corsCfg enableConsole = do cacheRef <- lift $ do pgResp <- liftIO $ runExceptT $ Q.runTx pool (Q.Serializable, Nothing) $ do Q.catchE defaultTxErrorHandler initStateTx @@ -376,13 +378,14 @@ app isoLevel mRootDir logger pool mode corsCfg = do liftIO $ putStrLn "HasuraDB is now waiting for connections" - maybe (return ()) (middleware . MS.staticPolicy . MS.addBase) mRootDir - -- cors middleware unless (ccDisabled corsCfg) $ middleware $ corsMiddleware (mkDefaultCorsPolicy $ ccDomain corsCfg) - get root $ html $ T.pack landingPage + -- API Console and Root Dir + if enableConsole then serveApiConsole consoleHTML + else maybe (return ()) (middleware . MS.staticPolicy . MS.addBase) mRootDir + get ("v1/template" var) $ tmpltGetOrDeleteH serverCtx post ("v1/template" var) $ tmpltPutOrPostH serverCtx put ("v1/template" var) $ tmpltPutOrPostH serverCtx @@ -428,3 +431,7 @@ app isoLevel mRootDir logger pool mode corsCfg = do mkQTemplateAction tmpltName tmpltArgs = v1QueryHandler $ RQExecuteQueryTemplate $ ExecQueryTemplate (TQueryName tmpltName) tmpltArgs + + serveApiConsole htmlFile = do + get root $ redirect "/console" + get ("console" wildcard) $ const $ html htmlFile diff --git a/server/src-lib/Hasura/Server/Init.hs b/server/src-lib/Hasura/Server/Init.hs index 1b38e133..50aa227c 100644 --- a/server/src-lib/Hasura/Server/Init.hs +++ b/server/src-lib/Hasura/Server/Init.hs @@ -171,3 +171,8 @@ parseWebHook = optional $ strOption ( long "auth-hook" <> metavar "AUTHENTICATION WEB HOOK" <> help "The authentication webhook, required to authenticate requests" ) + +parseEnableConsole :: Parser Bool +parseEnableConsole = switch ( long "enable-console" <> + help "Enable API Console" + ) diff --git a/server/src-rsr/console.html b/server/src-rsr/console.html new file mode 100644 index 00000000..1caa4c1e --- /dev/null +++ b/server/src-rsr/console.html @@ -0,0 +1,49 @@ + + + + + + + + +
+
+ + Loading... + +
+
+
+ + + + + + \ No newline at end of file diff --git a/server/src-rsr/landing_page.html b/server/src-rsr/landing_page.html deleted file mode 100644 index 603b00e1..00000000 --- a/server/src-rsr/landing_page.html +++ /dev/null @@ -1,449 +0,0 @@ - - - - - - - Hi! Your GraphQL endpoint on Postgres is ready. - - - - - - -
-

Hi! Your GraphQL endpoint on Postgres is ready.

-

Now, start building your schema and exploring your GraphQL APIs:

-

Step 1: Install the Hasura CLI

-
Mac / Linux
-
-
curl -L https://cli.hasura.io/install.sh | bash
- Copy -
-
Windows
- -

Step 2: Initialize a project

-
-

-            Copy
-        
-

Step 3: Open the Hasura Console

-
-
cd my-project && hasura console
- Copy -
-
- - - - - - diff --git a/server/test/Main.hs b/server/test/Main.hs index 4743525e..b41d0fd8 100644 --- a/server/test/Main.hs +++ b/server/test/Main.hs @@ -235,7 +235,7 @@ raven_app rlogger pool = do _ <- liftIO $ runExceptT $ Q.runTx pool defTxMode resetStateTx let corsCfg = CorsConfig "*" True -- cors is disabled - spockAsApp $ spockT id $ app Q.Serializable Nothing rlogger pool AMNoAuth corsCfg -- no access key and no webhook + spockAsApp $ spockT id $ app Q.Serializable Nothing rlogger pool AMNoAuth corsCfg True -- no access key and no webhook main :: IO () main = withStdoutLogger ravenLogGen $ \rlogger -> do