+4
-1
@@ -19,6 +19,7 @@ import qualified Hasql.Decoders as HD
|
|||||||
import qualified Hasql.Encoders as HE
|
import qualified Hasql.Encoders as HE
|
||||||
import qualified Hasql.Pool as P
|
import qualified Hasql.Pool as P
|
||||||
import Network.Wai.Handler.Warp
|
import Network.Wai.Handler.Warp
|
||||||
|
import Network.BSD (getHostName)
|
||||||
import System.IO (BufferMode (..),
|
import System.IO (BufferMode (..),
|
||||||
hSetBuffering, stderr,
|
hSetBuffering, stderr,
|
||||||
stdin, stdout)
|
stdin, stdout)
|
||||||
@@ -46,7 +47,9 @@ main = do
|
|||||||
hSetBuffering stdin LineBuffering
|
hSetBuffering stdin LineBuffering
|
||||||
hSetBuffering stderr NoBuffering
|
hSetBuffering stderr NoBuffering
|
||||||
|
|
||||||
conf <- readOptions
|
conf' <- readOptions
|
||||||
|
host <- getHostName
|
||||||
|
conf <- return conf' { configHost = host }
|
||||||
let port = configPort conf
|
let port = configPort conf
|
||||||
pgSettings = cs (configDatabase conf)
|
pgSettings = cs (configDatabase conf)
|
||||||
appSettings = setPort port
|
appSettings = setPort port
|
||||||
|
|||||||
+19
-6
@@ -44,8 +44,8 @@ executable postgrest
|
|||||||
, http-types
|
, http-types
|
||||||
, interpolatedstring-perl6
|
, interpolatedstring-perl6
|
||||||
, jwt
|
, jwt
|
||||||
, microlens >= 0.4.2 && < 0.5
|
, lens >=3.8 && < 5.0
|
||||||
, microlens-aeson >= 2.1.1 && < 2.2
|
, lens-aeson >= 1.0.0.0 && < 1.1.0.0
|
||||||
, mtl
|
, mtl
|
||||||
, optparse-applicative >= 0.11 && < 0.13
|
, optparse-applicative >= 0.11 && < 0.13
|
||||||
, parsec
|
, parsec
|
||||||
@@ -65,6 +65,10 @@ executable postgrest
|
|||||||
, wai-extra
|
, wai-extra
|
||||||
, wai-middleware-static >= 0.6.0
|
, wai-middleware-static >= 0.6.0
|
||||||
, warp >= 3.1.0
|
, warp >= 3.1.0
|
||||||
|
, insert-ordered-containers >= 0.1.0.1
|
||||||
|
, http-media >= 0.6.3
|
||||||
|
, swagger2 >= 2.1
|
||||||
|
, network >= 2.6.2.1
|
||||||
, HTTP
|
, HTTP
|
||||||
, Ranged-sets
|
, Ranged-sets
|
||||||
if !os(windows)
|
if !os(windows)
|
||||||
@@ -89,8 +93,8 @@ library
|
|||||||
, http-types
|
, http-types
|
||||||
, interpolatedstring-perl6
|
, interpolatedstring-perl6
|
||||||
, jwt
|
, jwt
|
||||||
, microlens
|
, lens
|
||||||
, microlens-aeson
|
, lens-aeson
|
||||||
, mtl
|
, mtl
|
||||||
, optparse-applicative
|
, optparse-applicative
|
||||||
, parsec
|
, parsec
|
||||||
@@ -109,6 +113,10 @@ library
|
|||||||
, wai-extra
|
, wai-extra
|
||||||
, wai-middleware-static >= 0.6.0
|
, wai-middleware-static >= 0.6.0
|
||||||
, warp >= 3.1.0
|
, warp >= 3.1.0
|
||||||
|
, insert-ordered-containers >= 0.1.0.1
|
||||||
|
, http-media >= 0.6.3
|
||||||
|
, swagger2 >= 2.1
|
||||||
|
, network >= 2.6.2.1
|
||||||
|
|
||||||
Other-Modules: Paths_postgrest
|
Other-Modules: Paths_postgrest
|
||||||
Exposed-Modules: PostgREST.App
|
Exposed-Modules: PostgREST.App
|
||||||
@@ -122,6 +130,7 @@ library
|
|||||||
, PostgREST.RangeQuery
|
, PostgREST.RangeQuery
|
||||||
, PostgREST.ApiRequest
|
, PostgREST.ApiRequest
|
||||||
, PostgREST.Types
|
, PostgREST.Types
|
||||||
|
, PostgREST.ApiSpec
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
|
|
||||||
Test-Suite spec
|
Test-Suite spec
|
||||||
@@ -163,8 +172,8 @@ Test-Suite spec
|
|||||||
, http-types
|
, http-types
|
||||||
, interpolatedstring-perl6
|
, interpolatedstring-perl6
|
||||||
, jwt
|
, jwt
|
||||||
, microlens
|
, lens
|
||||||
, microlens-aeson
|
, lens-aeson
|
||||||
, monad-control
|
, monad-control
|
||||||
, mtl
|
, mtl
|
||||||
, optparse-applicative
|
, optparse-applicative
|
||||||
@@ -186,5 +195,9 @@ Test-Suite spec
|
|||||||
, wai-extra
|
, wai-extra
|
||||||
, wai-middleware-static
|
, wai-middleware-static
|
||||||
, warp
|
, warp
|
||||||
|
, insert-ordered-containers
|
||||||
|
, http-media
|
||||||
|
, swagger2
|
||||||
|
, network
|
||||||
, HTTP
|
, HTTP
|
||||||
, Ranged-sets
|
, Ranged-sets
|
||||||
|
|||||||
@@ -0,0 +1,204 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
module PostgREST.ApiSpec (
|
||||||
|
apiSpec
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Control.Lens
|
||||||
|
import Data.Aeson (decode, encode)
|
||||||
|
import Data.HashMap.Strict.InsOrd (InsOrdHashMap, fromList)
|
||||||
|
import Data.String (IsString (..))
|
||||||
|
import Data.Text (Text, unpack, pack, concat, intercalate)
|
||||||
|
import Network.HTTP.Media (MediaType)
|
||||||
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
|
import Prelude hiding (concat)
|
||||||
|
|
||||||
|
import Data.Swagger
|
||||||
|
|
||||||
|
import PostgREST.ApiRequest (ContentType(..))
|
||||||
|
import PostgREST.Config (prettyVersion)
|
||||||
|
import PostgREST.QueryBuilder (operators)
|
||||||
|
import PostgREST.Types (Table(..), Column(..))
|
||||||
|
|
||||||
|
makeMimeList :: [MediaType]
|
||||||
|
makeMimeList = map (fromString . show) [ApplicationJSON, TextCSV]
|
||||||
|
|
||||||
|
toSwaggerType :: Text -> SwaggerType t
|
||||||
|
toSwaggerType "text" = SwaggerString
|
||||||
|
toSwaggerType "integer" = SwaggerInteger
|
||||||
|
toSwaggerType "boolean" = SwaggerBoolean
|
||||||
|
toSwaggerType "numeric" = SwaggerNumber
|
||||||
|
toSwaggerType _ = SwaggerString
|
||||||
|
|
||||||
|
makeProperty :: Column -> (Text, Referenced Schema)
|
||||||
|
makeProperty c = (colName c, Inline $ u)
|
||||||
|
where
|
||||||
|
r = (mempty :: Schema)
|
||||||
|
s = if null $ colEnum c
|
||||||
|
then r
|
||||||
|
else r & enum_ .~ decode (encode (colEnum c))
|
||||||
|
t = s & type_ .~ (toSwaggerType $ colType c)
|
||||||
|
u = t & format ?~ colType c
|
||||||
|
|
||||||
|
makeProperties :: [Column] -> InsOrdHashMap Text (Referenced Schema)
|
||||||
|
makeProperties cs = fromList $ map makeProperty cs
|
||||||
|
|
||||||
|
makeDefinition :: (Table, [Column], [Text]) -> (Text, Schema)
|
||||||
|
makeDefinition (t, cs, _) =
|
||||||
|
let tn = tableName t in
|
||||||
|
(tn, (mempty :: Schema)
|
||||||
|
& type_ .~ SwaggerObject
|
||||||
|
& properties .~ (makeProperties cs))
|
||||||
|
|
||||||
|
makeDefinitions :: [(Table, [Column], [Text])] -> InsOrdHashMap Text Schema
|
||||||
|
makeDefinitions ti = fromList $ map makeDefinition ti
|
||||||
|
|
||||||
|
makeOperatorPattern :: Text
|
||||||
|
makeOperatorPattern =
|
||||||
|
intercalate "|"
|
||||||
|
[ concat ["^", x, y, "[.]"] |
|
||||||
|
x <- ["not[.]", ""],
|
||||||
|
y <- map fst operators ]
|
||||||
|
|
||||||
|
makeRowFilter :: Column -> Param
|
||||||
|
makeRowFilter c =
|
||||||
|
(mempty :: Param)
|
||||||
|
& name .~ colName c
|
||||||
|
& required ?~ False
|
||||||
|
& schema .~ ParamOther ((mempty :: ParamOtherSchema)
|
||||||
|
& in_ .~ ParamQuery
|
||||||
|
& type_ .~ SwaggerString
|
||||||
|
& format ?~ colType c
|
||||||
|
& pattern ?~ makeOperatorPattern)
|
||||||
|
|
||||||
|
makeRowFilters :: [Column] -> [Param]
|
||||||
|
makeRowFilters cs = map makeRowFilter cs
|
||||||
|
|
||||||
|
makeOrderItems :: [Column] -> [Text]
|
||||||
|
makeOrderItems cs =
|
||||||
|
[ concat [x, y, z] |
|
||||||
|
x <- map colName cs,
|
||||||
|
y <- [".asc", ".desc", ""],
|
||||||
|
z <- [".nullsfirst", ".nulllast", ""]
|
||||||
|
]
|
||||||
|
|
||||||
|
makeRangeParams :: [Param]
|
||||||
|
makeRangeParams =
|
||||||
|
[ (mempty :: Param)
|
||||||
|
& name .~ "Range"
|
||||||
|
& description ?~ "Limiting and Pagination"
|
||||||
|
& required ?~ False
|
||||||
|
& schema .~ ParamOther ((mempty :: ParamOtherSchema)
|
||||||
|
& in_ .~ ParamHeader
|
||||||
|
& type_ .~ SwaggerString)
|
||||||
|
, (mempty :: Param)
|
||||||
|
& name .~ "Range-Unit"
|
||||||
|
& description ?~ "Limiting and Pagination"
|
||||||
|
& required ?~ False
|
||||||
|
& schema .~ ParamOther ((mempty :: ParamOtherSchema)
|
||||||
|
& in_ .~ ParamHeader
|
||||||
|
& type_ .~ SwaggerString
|
||||||
|
& default_ .~ decode "\"items\"")
|
||||||
|
, (mempty :: Param)
|
||||||
|
& name .~ "offset"
|
||||||
|
& description ?~ "Limiting and Pagination"
|
||||||
|
& required ?~ False
|
||||||
|
& schema .~ ParamOther ((mempty :: ParamOtherSchema)
|
||||||
|
& in_ .~ ParamQuery
|
||||||
|
& type_ .~ SwaggerString)
|
||||||
|
, (mempty :: Param)
|
||||||
|
& name .~ "limit"
|
||||||
|
& description ?~ "Limiting and Pagination"
|
||||||
|
& required ?~ False
|
||||||
|
& schema .~ ParamOther ((mempty :: ParamOtherSchema)
|
||||||
|
& in_ .~ ParamQuery
|
||||||
|
& type_ .~ SwaggerString)
|
||||||
|
]
|
||||||
|
|
||||||
|
makePreferParam :: [Text] -> Param
|
||||||
|
makePreferParam ts =
|
||||||
|
(mempty :: Param)
|
||||||
|
& name .~ "Prefer"
|
||||||
|
& description ?~ "Preference"
|
||||||
|
& required ?~ False
|
||||||
|
& schema .~ ParamOther ((mempty :: ParamOtherSchema)
|
||||||
|
& in_ .~ ParamHeader
|
||||||
|
& type_ .~ SwaggerString
|
||||||
|
& enum_ .~ decode (encode ts))
|
||||||
|
|
||||||
|
makeGetParams :: [Column] -> [Param]
|
||||||
|
makeGetParams cs =
|
||||||
|
makeRangeParams ++
|
||||||
|
[ (mempty :: Param)
|
||||||
|
& name .~ "select"
|
||||||
|
& description ?~ "Filtering Columns"
|
||||||
|
& required ?~ False
|
||||||
|
& schema .~ ParamOther ((mempty :: ParamOtherSchema)
|
||||||
|
& in_ .~ ParamQuery
|
||||||
|
& type_ .~ SwaggerString)
|
||||||
|
, (mempty :: Param)
|
||||||
|
& name .~ "order"
|
||||||
|
& description ?~ "Ordering"
|
||||||
|
& required ?~ False
|
||||||
|
& schema .~ ParamOther ((mempty :: ParamOtherSchema)
|
||||||
|
& in_ .~ ParamQuery
|
||||||
|
& type_ .~ SwaggerString
|
||||||
|
& enum_ .~ decode (encode $ makeOrderItems cs))
|
||||||
|
, makePreferParam ["plurality=singular", "count=none"]
|
||||||
|
]
|
||||||
|
|
||||||
|
makePostParams :: Text -> [Param]
|
||||||
|
makePostParams tn =
|
||||||
|
[ makePreferParam ["return=representation", "return=minimal"]
|
||||||
|
, (mempty :: Param)
|
||||||
|
& name .~ "body"
|
||||||
|
& description ?~ tn
|
||||||
|
& required ?~ False
|
||||||
|
& schema .~ ParamBody (Ref (Reference tn))
|
||||||
|
]
|
||||||
|
|
||||||
|
makeDeleteParams :: [Param]
|
||||||
|
makeDeleteParams =
|
||||||
|
[ makePreferParam ["return=representation", "return=minimal"] ]
|
||||||
|
|
||||||
|
makePathItem :: (Table, [Column], [Text]) -> (FilePath, PathItem)
|
||||||
|
makePathItem (t, cs, _) = ("/" ++ (unpack tn), p $ tableInsertable t)
|
||||||
|
where
|
||||||
|
tOp = (mempty :: Operation)
|
||||||
|
& tags .~ Set.fromList [tn]
|
||||||
|
& produces ?~ MimeList makeMimeList
|
||||||
|
& at 200 ?~ "OK"
|
||||||
|
getOp = tOp
|
||||||
|
& parameters .~ map Inline (makeGetParams cs ++ rs)
|
||||||
|
postOp = tOp
|
||||||
|
& consumes ?~ MimeList makeMimeList
|
||||||
|
& parameters .~ map Inline (makePostParams tn)
|
||||||
|
patchOp = tOp
|
||||||
|
& consumes ?~ MimeList makeMimeList
|
||||||
|
& parameters .~ map Inline (makePostParams tn ++ rs)
|
||||||
|
deletOp = tOp
|
||||||
|
& parameters .~ map Inline (makeDeleteParams ++ rs)
|
||||||
|
pr = (mempty :: PathItem) & get ?~ getOp
|
||||||
|
pw = pr & post ?~ postOp & patch ?~ patchOp & delete ?~ deletOp
|
||||||
|
p False = pr
|
||||||
|
p True = pw
|
||||||
|
rs = makeRowFilters cs
|
||||||
|
tn = tableName t
|
||||||
|
|
||||||
|
makePathItems :: [(Table, [Column], [Text])] -> InsOrdHashMap FilePath PathItem
|
||||||
|
makePathItems ti = fromList (map makePathItem ti)
|
||||||
|
|
||||||
|
apiSpec :: [(Table, [Column], [Text])] -> String -> Integer -> Swagger
|
||||||
|
apiSpec ti h p = (mempty :: Swagger)
|
||||||
|
& basePath ?~ "/"
|
||||||
|
& schemes ?~ [Http]
|
||||||
|
& info .~ ((mempty :: Info)
|
||||||
|
& version .~ (pack prettyVersion)
|
||||||
|
& title .~ "PostgREST API"
|
||||||
|
& description ?~ "This is a dynamic API generated by PostgREST")
|
||||||
|
& host .~ h'
|
||||||
|
& definitions .~ (makeDefinitions ti)
|
||||||
|
& paths .~ (makePathItems ti)
|
||||||
|
where
|
||||||
|
h' = Just $ Host h (Just (fromInteger p))
|
||||||
+18
-4
@@ -9,6 +9,7 @@ module PostgREST.App (
|
|||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Data.Bifunctor (first)
|
import Data.Bifunctor (first)
|
||||||
import qualified Data.ByteString.Char8 as BS
|
import qualified Data.ByteString.Char8 as BS
|
||||||
|
import qualified Data.ByteString.Lazy as BL
|
||||||
import Data.IORef (IORef, readIORef)
|
import Data.IORef (IORef, readIORef)
|
||||||
import Data.List (find, delete)
|
import Data.List (find, delete)
|
||||||
import Data.Maybe (fromMaybe, fromJust, mapMaybe)
|
import Data.Maybe (fromMaybe, fromJust, mapMaybe)
|
||||||
@@ -60,6 +61,7 @@ import PostgREST.QueryBuilder ( callProc
|
|||||||
, ResultsWithCount
|
, ResultsWithCount
|
||||||
)
|
)
|
||||||
import PostgREST.Types
|
import PostgREST.Types
|
||||||
|
import PostgREST.ApiSpec
|
||||||
|
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
@@ -180,9 +182,6 @@ app dbStructure conf apiRequest =
|
|||||||
let cols = filter (filterCol tSchema tTable) $ dbColumns dbStructure
|
let cols = filter (filterCol tSchema tTable) $ dbColumns dbStructure
|
||||||
pkeys = map pkName $ filter (filterPk tSchema tTable) allPrKeys
|
pkeys = map pkName $ filter (filterPk tSchema tTable) allPrKeys
|
||||||
body = encode (TableOptions cols pkeys)
|
body = encode (TableOptions cols pkeys)
|
||||||
filterCol :: Schema -> TableName -> Column -> Bool
|
|
||||||
filterCol sc tb Column{colTable=Table{tableSchema=s, tableName=t}} = s==sc && t==tb
|
|
||||||
filterCol _ _ _ = False
|
|
||||||
acceptH = (hAllow, if tableInsertable table then "GET,POST,PATCH,DELETE" else "GET") in
|
acceptH = (hAllow, if tableInsertable table then "GET,POST,PATCH,DELETE" else "GET") in
|
||||||
return $ responseLBS status200 [jsonH, allOrigins, acceptH] $ cs body
|
return $ responseLBS status200 [jsonH, allOrigins, acceptH] $ cs body
|
||||||
|
|
||||||
@@ -206,7 +205,7 @@ app dbStructure conf apiRequest =
|
|||||||
else return notFound
|
else return notFound
|
||||||
|
|
||||||
(ActionRead, TargetRoot, Nothing) -> do
|
(ActionRead, TargetRoot, Nothing) -> do
|
||||||
body <- encode <$> H.query schema accessibleTables
|
body <- (encodeApi . toTableInfo) <$> H.query schema accessibleTables
|
||||||
return $ responseLBS status200 [jsonH] $ cs body
|
return $ responseLBS status200 [jsonH] $ cs body
|
||||||
|
|
||||||
(ActionInappropriate, _, _) -> return $ responseLBS status405 [] ""
|
(ActionInappropriate, _, _) -> return $ responseLBS status405 [] ""
|
||||||
@@ -220,8 +219,23 @@ app dbStructure conf apiRequest =
|
|||||||
(_, _, _) -> return notFound
|
(_, _, _) -> return notFound
|
||||||
|
|
||||||
where
|
where
|
||||||
|
toTableInfo :: [Table] -> [(Table, [Column], [Text])]
|
||||||
|
toTableInfo ts = map (\t ->
|
||||||
|
let tSchema = tableSchema t
|
||||||
|
tTable = tableName t
|
||||||
|
cols = filter (filterCol tSchema tTable) $ dbColumns dbStructure
|
||||||
|
pkeys = map pkName $ filter (filterPk tSchema tTable) allPrKeys
|
||||||
|
in
|
||||||
|
(t, cols, pkeys)) ts
|
||||||
|
encodeApi :: [(Table, [Column], [Text])] -> BL.ByteString
|
||||||
|
encodeApi ti = encode $ apiSpec ti host port
|
||||||
|
host = configHost conf
|
||||||
|
port = toInteger $ configPort conf
|
||||||
notFound = responseLBS status404 [] ""
|
notFound = responseLBS status404 [] ""
|
||||||
filterPk sc table pk = sc == (tableSchema . pkTable) pk && table == (tableName . pkTable) pk
|
filterPk sc table pk = sc == (tableSchema . pkTable) pk && table == (tableName . pkTable) pk
|
||||||
|
filterCol :: Schema -> TableName -> Column -> Bool
|
||||||
|
filterCol sc tb Column{colTable=Table{tableSchema=s, tableName=t}} = s==sc && t==tb
|
||||||
|
filterCol _ _ _ = False
|
||||||
allPrKeys = dbPrimaryKeys dbStructure
|
allPrKeys = dbPrimaryKeys dbStructure
|
||||||
allOrigins = ("Access-Control-Allow-Origin", "*") :: Header
|
allOrigins = ("Access-Control-Allow-Origin", "*") :: Header
|
||||||
schema = cs $ configSchema conf
|
schema = cs $ configSchema conf
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ module PostgREST.Auth (
|
|||||||
, tokenJWT
|
, tokenJWT
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Lens.Micro
|
import Control.Lens
|
||||||
import Lens.Micro.Aeson
|
|
||||||
import Data.Aeson (Value (..), parseJSON, toJSON)
|
import Data.Aeson (Value (..), parseJSON, toJSON)
|
||||||
|
import Data.Aeson.Lens
|
||||||
import Data.Aeson.Types (parseMaybe, emptyObject, emptyArray)
|
import Data.Aeson.Types (parseMaybe, emptyObject, emptyArray)
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.Vector as V
|
import qualified Data.Vector as V
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ data AppConfig = AppConfig {
|
|||||||
configDatabase :: String
|
configDatabase :: String
|
||||||
, configAnonRole :: String
|
, configAnonRole :: String
|
||||||
, configSchema :: String
|
, configSchema :: String
|
||||||
|
, configHost :: String
|
||||||
, configPort :: Int
|
, configPort :: Int
|
||||||
, configJwtSecret :: Secret
|
, configJwtSecret :: Secret
|
||||||
, configPool :: Int
|
, configPool :: Int
|
||||||
@@ -51,6 +52,7 @@ argParser = AppConfig
|
|||||||
<$> argument str (help "(REQUIRED) database connection string, e.g. postgres://user:pass@host:port/db" <> metavar "DB_URL")
|
<$> argument str (help "(REQUIRED) database connection string, e.g. postgres://user:pass@host:port/db" <> metavar "DB_URL")
|
||||||
<*> strOption (long "anonymous" <> short 'a' <> help "(REQUIRED) postgres role to use for non-authenticated requests" <> metavar "ROLE")
|
<*> strOption (long "anonymous" <> short 'a' <> help "(REQUIRED) postgres role to use for non-authenticated requests" <> metavar "ROLE")
|
||||||
<*> strOption (long "schema" <> short 's' <> help "schema to use for API routes" <> metavar "NAME" <> value "public" <> showDefault)
|
<*> strOption (long "schema" <> short 's' <> help "schema to use for API routes" <> metavar "NAME" <> value "public" <> showDefault)
|
||||||
|
<*> pure "localhost"
|
||||||
<*> option auto (long "port" <> short 'p' <> help "port number on which to run HTTP server" <> metavar "PORT" <> value 3000 <> showDefault)
|
<*> option auto (long "port" <> short 'p' <> help "port number on which to run HTTP server" <> metavar "PORT" <> value 3000 <> showDefault)
|
||||||
<*> (secret . cs <$>
|
<*> (secret . cs <$>
|
||||||
strOption (long "jwt-secret" <> short 'j' <> help "secret used to encrypt and decrypt JWT tokens" <> metavar "SECRET" <> value "secret" <> showDefault))
|
strOption (long "jwt-secret" <> short 'j' <> help "secret used to encrypt and decrypt JWT tokens" <> metavar "SECRET" <> value "secret" <> showDefault))
|
||||||
|
|||||||
+5
-1
@@ -16,7 +16,11 @@ extra-deps:
|
|||||||
- wai-cors-0.2.5
|
- wai-cors-0.2.5
|
||||||
- cryptohash-sha256-0.11.100.0
|
- cryptohash-sha256-0.11.100.0
|
||||||
- hackage-security-0.5.2.1
|
- hackage-security-0.5.2.1
|
||||||
|
- unordered-containers-0.2.7.1
|
||||||
|
- insert-ordered-containers-0.1.0.1
|
||||||
|
- swagger2-2.1
|
||||||
|
- http-media-0.6.3
|
||||||
|
- network-2.6.2.1
|
||||||
ghc-options:
|
ghc-options:
|
||||||
postgrest: -O2 -Werror -Wall -fwarn-identities
|
postgrest: -O2 -Werror -Wall -fwarn-identities
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user