committed by
Steve Chavez
parent
3cd3a3f8c6
commit
77cd9387d4
+15
-16
@@ -53,8 +53,7 @@ import PostgREST.Config (AppConfig (..),
|
|||||||
OpenAPIMode (..))
|
OpenAPIMode (..))
|
||||||
import PostgREST.MediaType (MTPlanAttrs (..),
|
import PostgREST.MediaType (MTPlanAttrs (..),
|
||||||
MTPlanFormat (..),
|
MTPlanFormat (..),
|
||||||
MediaType (..),
|
MediaType (..))
|
||||||
NormalMedia (..))
|
|
||||||
import PostgREST.RangeQuery (NonnegRange, allRange,
|
import PostgREST.RangeQuery (NonnegRange, allRange,
|
||||||
convertToLimitZeroRange,
|
convertToLimitZeroRange,
|
||||||
hasLimitZero,
|
hasLimitZero,
|
||||||
@@ -211,8 +210,8 @@ getMediaTypes conf hdrs action path = do
|
|||||||
acceptMediaType <- negotiateContent conf action path accepts
|
acceptMediaType <- negotiateContent conf action path accepts
|
||||||
pure (acceptMediaType, contentMediaType)
|
pure (acceptMediaType, contentMediaType)
|
||||||
where
|
where
|
||||||
accepts = maybe [MTNormal MTAny] (map MediaType.decodeMediaType . parseHttpAccept) $ lookupHeader "accept"
|
accepts = maybe [MTAny] (map MediaType.decodeMediaType . parseHttpAccept) $ lookupHeader "accept"
|
||||||
contentMediaType = maybe (MTNormal MTApplicationJSON) MediaType.decodeMediaType $ lookupHeader "content-type"
|
contentMediaType = maybe MTApplicationJSON MediaType.decodeMediaType $ lookupHeader "content-type"
|
||||||
lookupHeader = flip lookup hdrs
|
lookupHeader = flip lookup hdrs
|
||||||
|
|
||||||
getSchema :: AppConfig -> RequestHeaders -> ByteString -> Either ApiRequestError (Schema, Bool)
|
getSchema :: AppConfig -> RequestHeaders -> ByteString -> Either ApiRequestError (Schema, Bool)
|
||||||
@@ -265,26 +264,26 @@ getPayload reqBody contentMediaType QueryParams{qsColumns} action PathInfo{pathI
|
|||||||
where
|
where
|
||||||
payload :: Either ApiRequestError (Maybe Payload)
|
payload :: Either ApiRequestError (Maybe Payload)
|
||||||
payload = mapBoth InvalidBody Just $ case (contentMediaType, pathIsProc) of
|
payload = mapBoth InvalidBody Just $ case (contentMediaType, pathIsProc) of
|
||||||
(MTNormal MTApplicationJSON, _) ->
|
(MTApplicationJSON, _) ->
|
||||||
if isJust columns
|
if isJust columns
|
||||||
then Right $ RawJSON reqBody
|
then Right $ RawJSON reqBody
|
||||||
else note "All object keys must match" . payloadAttributes reqBody
|
else note "All object keys must match" . payloadAttributes reqBody
|
||||||
=<< if LBS.null reqBody && pathIsProc
|
=<< if LBS.null reqBody && pathIsProc
|
||||||
then Right emptyObject
|
then Right emptyObject
|
||||||
else first BS.pack $ JSON.eitherDecode reqBody
|
else first BS.pack $ JSON.eitherDecode reqBody
|
||||||
(MTNormal MTTextCSV, _) -> do
|
(MTTextCSV, _) -> do
|
||||||
json <- csvToJson <$> first BS.pack (CSV.decodeByName reqBody)
|
json <- csvToJson <$> first BS.pack (CSV.decodeByName reqBody)
|
||||||
note "All lines must have same number of fields" $ payloadAttributes (JSON.encode json) json
|
note "All lines must have same number of fields" $ payloadAttributes (JSON.encode json) json
|
||||||
(MTNormal MTUrlEncoded, isProc) -> do
|
(MTUrlEncoded, isProc) -> do
|
||||||
let params = (T.decodeUtf8 *** T.decodeUtf8) <$> parseSimpleQuery (LBS.toStrict reqBody)
|
let params = (T.decodeUtf8 *** T.decodeUtf8) <$> parseSimpleQuery (LBS.toStrict reqBody)
|
||||||
if isProc
|
if isProc
|
||||||
then Right $ ProcessedUrlEncoded params (S.fromList $ fst <$> params)
|
then Right $ ProcessedUrlEncoded params (S.fromList $ fst <$> params)
|
||||||
else
|
else
|
||||||
let paramsMap = HM.fromList $ (identity *** JSON.String) <$> params in
|
let paramsMap = HM.fromList $ (identity *** JSON.String) <$> params in
|
||||||
Right $ ProcessedJSON (JSON.encode paramsMap) $ S.fromList (HM.keys paramsMap)
|
Right $ ProcessedJSON (JSON.encode paramsMap) $ S.fromList (HM.keys paramsMap)
|
||||||
(MTNormal MTTextPlain, True) -> Right $ RawPay reqBody
|
(MTTextPlain, True) -> Right $ RawPay reqBody
|
||||||
(MTNormal MTTextXML, True) -> Right $ RawPay reqBody
|
(MTTextXML, True) -> Right $ RawPay reqBody
|
||||||
(MTNormal MTOctetStream, True) -> Right $ RawPay reqBody
|
(MTOctetStream, True) -> Right $ RawPay reqBody
|
||||||
(ct, _) -> Left $ "Content-Type not acceptable: " <> MediaType.toMime ct
|
(ct, _) -> Left $ "Content-Type not acceptable: " <> MediaType.toMime ct
|
||||||
|
|
||||||
shouldParsePayload = case (action, contentMediaType) of
|
shouldParsePayload = case (action, contentMediaType) of
|
||||||
@@ -354,7 +353,7 @@ payloadAttributes raw json =
|
|||||||
negotiateContent :: AppConfig -> Action -> PathInfo -> [MediaType] -> Either ApiRequestError MediaType
|
negotiateContent :: AppConfig -> Action -> PathInfo -> [MediaType] -> Either ApiRequestError MediaType
|
||||||
negotiateContent conf action path accepts =
|
negotiateContent conf action path accepts =
|
||||||
case firstAcceptedPick of
|
case firstAcceptedPick of
|
||||||
Just (MTNormal MTAny) -> Right (MTNormal MTApplicationJSON) -- by default(for */*) we respond with json
|
Just MTAny -> Right MTApplicationJSON -- by default(for */*) we respond with json
|
||||||
Just mt -> Right mt
|
Just mt -> Right mt
|
||||||
Nothing -> Left . MediaTypeError $ map MediaType.toMime accepts
|
Nothing -> Left . MediaTypeError $ map MediaType.toMime accepts
|
||||||
where
|
where
|
||||||
@@ -366,15 +365,15 @@ producedMediaTypes conf action path =
|
|||||||
case action of
|
case action of
|
||||||
ActionRead _ -> defaultMediaTypes ++ rawMediaTypes
|
ActionRead _ -> defaultMediaTypes ++ rawMediaTypes
|
||||||
ActionInvoke _ -> invokeMediaTypes
|
ActionInvoke _ -> invokeMediaTypes
|
||||||
ActionInspect _ -> [MTNormal MTOpenAPI, MTNormal MTApplicationJSON, MTNormal MTAny]
|
ActionInspect _ -> [MTOpenAPI, MTApplicationJSON, MTAny]
|
||||||
ActionInfo -> defaultMediaTypes
|
ActionInfo -> defaultMediaTypes
|
||||||
ActionMutate _ -> defaultMediaTypes
|
ActionMutate _ -> defaultMediaTypes
|
||||||
where
|
where
|
||||||
invokeMediaTypes =
|
invokeMediaTypes =
|
||||||
defaultMediaTypes
|
defaultMediaTypes
|
||||||
++ rawMediaTypes
|
++ rawMediaTypes
|
||||||
++ [MTNormal MTOpenAPI | pathIsRootSpec path]
|
++ [MTOpenAPI | pathIsRootSpec path]
|
||||||
defaultMediaTypes =
|
defaultMediaTypes =
|
||||||
[MTNormal MTApplicationJSON, MTNormal MTSingularJSON, MTNormal MTGeoJSON, MTNormal MTTextCSV] ++
|
[MTApplicationJSON, MTSingularJSON, MTGeoJSON, MTTextCSV] ++
|
||||||
[MTPlan $ MTPlanAttrs Nothing PlanJSON mempty | configDbPlanEnabled conf] ++ [MTNormal MTAny]
|
[MTPlan $ MTPlanAttrs Nothing PlanJSON mempty | configDbPlanEnabled conf] ++ [MTAny]
|
||||||
rawMediaTypes = configRawMediaTypes conf `union` [MTNormal MTOctetStream, MTNormal MTTextPlain, MTNormal MTTextXML]
|
rawMediaTypes = configRawMediaTypes conf `union` [MTOctetStream, MTTextPlain, MTTextXML]
|
||||||
|
|||||||
@@ -57,8 +57,7 @@ import PostgREST.Config.JSPath (JSPath, JSPathExp (..),
|
|||||||
dumpJSPath, pRoleClaimKey)
|
dumpJSPath, pRoleClaimKey)
|
||||||
import PostgREST.Config.Proxy (Proxy (..),
|
import PostgREST.Config.Proxy (Proxy (..),
|
||||||
isMalformedProxyUri, toURI)
|
isMalformedProxyUri, toURI)
|
||||||
import PostgREST.MediaType (MediaType (..),
|
import PostgREST.MediaType (MediaType (..), toMime)
|
||||||
NormalMedia (..), toMime)
|
|
||||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier, dumpQi,
|
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier, dumpQi,
|
||||||
toQi)
|
toQi)
|
||||||
|
|
||||||
@@ -263,7 +262,7 @@ parser optPath env dbSettings roleSettings roleIsolationLvl =
|
|||||||
<*> parseOpenAPIMode "openapi-mode"
|
<*> parseOpenAPIMode "openapi-mode"
|
||||||
<*> (fromMaybe False <$> optBool "openapi-security-active")
|
<*> (fromMaybe False <$> optBool "openapi-security-active")
|
||||||
<*> parseOpenAPIServerProxyURI "openapi-server-proxy-uri"
|
<*> parseOpenAPIServerProxyURI "openapi-server-proxy-uri"
|
||||||
<*> (maybe [] (fmap (MTNormal . MTOther . encodeUtf8) . splitOnCommas) <$> optValue "raw-media-types")
|
<*> (maybe [] (fmap (MTOther . encodeUtf8) . splitOnCommas) <$> optValue "raw-media-types")
|
||||||
<*> (fromMaybe "!4" <$> optString "server-host")
|
<*> (fromMaybe "!4" <$> optString "server-host")
|
||||||
<*> (fromMaybe 3000 <$> optInt "server-port")
|
<*> (fromMaybe 3000 <$> optInt "server-port")
|
||||||
<*> (fmap (CI.mk . encodeUtf8) <$> optString "server-trace-header")
|
<*> (fmap (CI.mk . encodeUtf8) <$> optString "server-trace-header")
|
||||||
|
|||||||
+14
-15
@@ -33,8 +33,7 @@ import Network.HTTP.Types.Header (Header)
|
|||||||
import PostgREST.ApiRequest.Types (ApiRequestError (..),
|
import PostgREST.ApiRequest.Types (ApiRequestError (..),
|
||||||
QPError (..),
|
QPError (..),
|
||||||
RangeError (..))
|
RangeError (..))
|
||||||
import PostgREST.MediaType (MediaType (..),
|
import PostgREST.MediaType (MediaType (..))
|
||||||
NormalMedia (..))
|
|
||||||
import qualified PostgREST.MediaType as MediaType
|
import qualified PostgREST.MediaType as MediaType
|
||||||
|
|
||||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
|
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
|
||||||
@@ -82,7 +81,7 @@ instance PgrstError ApiRequestError where
|
|||||||
status LimitNoOrderError = HTTP.status400
|
status LimitNoOrderError = HTTP.status400
|
||||||
status ColumnNotFound{} = HTTP.status400
|
status ColumnNotFound{} = HTTP.status400
|
||||||
|
|
||||||
headers _ = [MediaType.toContentType $ MTNormal MTApplicationJSON]
|
headers _ = [MediaType.toContentType MTApplicationJSON]
|
||||||
|
|
||||||
instance JSON.ToJSON ApiRequestError where
|
instance JSON.ToJSON ApiRequestError where
|
||||||
toJSON (QueryParamError (QPError message details)) = JSON.object [
|
toJSON (QueryParamError (QPError message details)) = JSON.object [
|
||||||
@@ -189,17 +188,17 @@ instance JSON.ToJSON ApiRequestError where
|
|||||||
prmsMsg = "(" <> prms <> ")"
|
prmsMsg = "(" <> prms <> ")"
|
||||||
prmsDet = " with parameter" <> (if length argumentKeys > 1 then "s " else " ") <> prms
|
prmsDet = " with parameter" <> (if length argumentKeys > 1 then "s " else " ") <> prms
|
||||||
fmtPrms p = if null argumentKeys then " without parameters" else p
|
fmtPrms p = if null argumentKeys then " without parameters" else p
|
||||||
onlySingleParams = hasPreferSingleObject || (isInvPost && contentType `elem` [MTNormal MTTextPlain, MTNormal MTTextXML, MTNormal MTOctetStream])
|
onlySingleParams = hasPreferSingleObject || (isInvPost && contentType `elem` [MTTextPlain, MTTextXML, MTOctetStream])
|
||||||
in JSON.object [
|
in JSON.object [
|
||||||
"code" .= SchemaCacheErrorCode02,
|
"code" .= SchemaCacheErrorCode02,
|
||||||
"message" .= ("Could not find the function " <> func <> (if onlySingleParams then "" else fmtPrms prmsMsg) <> " in the schema cache"),
|
"message" .= ("Could not find the function " <> func <> (if onlySingleParams then "" else fmtPrms prmsMsg) <> " in the schema cache"),
|
||||||
"details" .= ("Searched for the function " <> func <>
|
"details" .= ("Searched for the function " <> func <>
|
||||||
(case (hasPreferSingleObject, isInvPost, contentType) of
|
(case (hasPreferSingleObject, isInvPost, contentType) of
|
||||||
(True, _, _) -> " with a single json/jsonb parameter"
|
(True, _, _) -> " with a single json/jsonb parameter"
|
||||||
(_, True, MTNormal MTTextPlain) -> " with a single unnamed text parameter"
|
(_, True, MTTextPlain) -> " with a single unnamed text parameter"
|
||||||
(_, True, MTNormal MTTextXML) -> " with a single unnamed xml parameter"
|
(_, True, MTTextXML) -> " with a single unnamed xml parameter"
|
||||||
(_, True, MTNormal MTOctetStream) -> " with a single unnamed bytea parameter"
|
(_, True, MTOctetStream) -> " with a single unnamed bytea parameter"
|
||||||
(_, True, MTNormal MTApplicationJSON) -> fmtPrms prmsDet <> " or with a single unnamed json/jsonb parameter"
|
(_, True, MTApplicationJSON) -> fmtPrms prmsDet <> " or with a single unnamed json/jsonb parameter"
|
||||||
_ -> fmtPrms prmsDet) <>
|
_ -> fmtPrms prmsDet) <>
|
||||||
", but no matches were found in the schema cache."),
|
", but no matches were found in the schema cache."),
|
||||||
-- The hint will be null in the case of single unnamed parameter functions
|
-- The hint will be null in the case of single unnamed parameter functions
|
||||||
@@ -362,8 +361,8 @@ instance PgrstError PgError where
|
|||||||
|
|
||||||
headers err =
|
headers err =
|
||||||
if status err == HTTP.status401
|
if status err == HTTP.status401
|
||||||
then [MediaType.toContentType $ MTNormal MTApplicationJSON, ("WWW-Authenticate", "Bearer") :: Header]
|
then [MediaType.toContentType MTApplicationJSON, ("WWW-Authenticate", "Bearer") :: Header]
|
||||||
else [MediaType.toContentType $ MTNormal MTApplicationJSON]
|
else [MediaType.toContentType MTApplicationJSON]
|
||||||
|
|
||||||
instance JSON.ToJSON PgError where
|
instance JSON.ToJSON PgError where
|
||||||
toJSON (PgError _ usageError) = JSON.toJSON usageError
|
toJSON (PgError _ usageError) = JSON.toJSON usageError
|
||||||
@@ -476,11 +475,11 @@ instance PgrstError Error where
|
|||||||
status SingularityError{} = HTTP.status406
|
status SingularityError{} = HTTP.status406
|
||||||
|
|
||||||
headers (ApiRequestError err) = headers err
|
headers (ApiRequestError err) = headers err
|
||||||
headers (JwtTokenInvalid m) = [MediaType.toContentType $ MTNormal MTApplicationJSON, invalidTokenHeader m]
|
headers (JwtTokenInvalid m) = [MediaType.toContentType MTApplicationJSON, invalidTokenHeader m]
|
||||||
headers JwtTokenRequired = [MediaType.toContentType $ MTNormal MTApplicationJSON, requiredTokenHeader]
|
headers JwtTokenRequired = [MediaType.toContentType MTApplicationJSON, requiredTokenHeader]
|
||||||
headers (PgErr err) = headers err
|
headers (PgErr err) = headers err
|
||||||
headers SingularityError{} = [MediaType.toContentType $ MTNormal MTSingularJSON]
|
headers SingularityError{} = [MediaType.toContentType MTSingularJSON]
|
||||||
headers _ = [MediaType.toContentType $ MTNormal MTApplicationJSON]
|
headers _ = [MediaType.toContentType MTApplicationJSON]
|
||||||
|
|
||||||
instance JSON.ToJSON Error where
|
instance JSON.ToJSON Error where
|
||||||
toJSON NoSchemaCacheError = JSON.object [
|
toJSON NoSchemaCacheError = JSON.object [
|
||||||
@@ -531,7 +530,7 @@ instance JSON.ToJSON Error where
|
|||||||
toJSON (SingularityError n) = JSON.object [
|
toJSON (SingularityError n) = JSON.object [
|
||||||
"code" .= ApiRequestErrorCode16,
|
"code" .= ApiRequestErrorCode16,
|
||||||
"message" .= ("JSON object requested, multiple (or no) rows returned" :: Text),
|
"message" .= ("JSON object requested, multiple (or no) rows returned" :: Text),
|
||||||
"details" .= T.unwords ["Results contain", show n, "rows,", T.decodeUtf8 (MediaType.toMime $ MTNormal MTSingularJSON), "requires 1 row"],
|
"details" .= T.unwords ["Results contain", show n, "rows,", T.decodeUtf8 (MediaType.toMime MTSingularJSON), "requires 1 row"],
|
||||||
"hint" .= JSON.Null]
|
"hint" .= JSON.Null]
|
||||||
|
|
||||||
toJSON (PgErr err) = JSON.toJSON err
|
toJSON (PgErr err) = JSON.toJSON err
|
||||||
|
|||||||
+42
-89
@@ -1,9 +1,7 @@
|
|||||||
{-# LANGUAGE DuplicateRecordFields #-}
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
{-# LANGUAGE LambdaCase #-}
|
|
||||||
|
|
||||||
module PostgREST.MediaType
|
module PostgREST.MediaType
|
||||||
( MediaType(..)
|
( MediaType(..)
|
||||||
, NormalMedia(..)
|
|
||||||
, MTPlanOption (..)
|
, MTPlanOption (..)
|
||||||
, MTPlanFormat (..)
|
, MTPlanFormat (..)
|
||||||
, MTPlanAttrs(..)
|
, MTPlanAttrs(..)
|
||||||
@@ -15,29 +13,14 @@ module PostgREST.MediaType
|
|||||||
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.ByteString.Internal as BS (c2w)
|
import qualified Data.ByteString.Internal as BS (c2w)
|
||||||
import qualified Data.List as L
|
|
||||||
import Data.Maybe (fromJust)
|
import Data.Maybe (fromJust)
|
||||||
|
|
||||||
import Network.HTTP.Types.Header (Header, hContentType)
|
import Network.HTTP.Types.Header (Header, hContentType)
|
||||||
|
|
||||||
import Protolude
|
import Protolude
|
||||||
--
|
|
||||||
-- $setup
|
|
||||||
-- Setup for doctests
|
|
||||||
-- >>> import Text.Pretty.Simple (pPrint)
|
|
||||||
-- >>> deriving instance Show NormalMedia
|
|
||||||
-- >>> deriving instance Show MTPlanFormat
|
|
||||||
-- >>> deriving instance Show MTPlanOption
|
|
||||||
-- >>> deriving instance Show MTPlanAttrs
|
|
||||||
-- >>> deriving instance Show MediaType
|
|
||||||
|
|
||||||
-- | Enumeration of currently supported media types
|
-- | Enumeration of currently supported media types
|
||||||
data MediaType
|
data MediaType
|
||||||
= MTNormal NormalMedia
|
|
||||||
| MTPlan MTPlanAttrs
|
|
||||||
deriving Eq
|
|
||||||
|
|
||||||
data NormalMedia
|
|
||||||
= MTApplicationJSON
|
= MTApplicationJSON
|
||||||
| MTSingularJSON
|
| MTSingularJSON
|
||||||
| MTGeoJSON
|
| MTGeoJSON
|
||||||
@@ -49,107 +32,61 @@ data NormalMedia
|
|||||||
| MTOctetStream
|
| MTOctetStream
|
||||||
| MTAny
|
| MTAny
|
||||||
| MTOther ByteString
|
| MTOther ByteString
|
||||||
|
| MTPlan MTPlanAttrs
|
||||||
deriving Eq
|
deriving Eq
|
||||||
|
|
||||||
|
data MTPlanAttrs = MTPlanAttrs (Maybe MediaType) MTPlanFormat [MTPlanOption]
|
||||||
data MTPlanAttrs = MTPlanAttrs (Maybe NormalMedia) MTPlanFormat [MTPlanOption]
|
|
||||||
instance Eq MTPlanAttrs where
|
instance Eq MTPlanAttrs where
|
||||||
MTPlanAttrs {} == MTPlanAttrs {} = True -- we don't care about the attributes when comparing two MTPlan media types
|
MTPlanAttrs {} == MTPlanAttrs {} = True -- we don't care about the attributes when comparing two MTPlan media types
|
||||||
|
|
||||||
data MTPlanOption
|
data MTPlanOption
|
||||||
= PlanAnalyze | PlanVerbose | PlanSettings | PlanBuffers | PlanWAL
|
= PlanAnalyze | PlanVerbose | PlanSettings | PlanBuffers | PlanWAL
|
||||||
deriving Eq
|
|
||||||
|
|
||||||
data MTPlanFormat
|
data MTPlanFormat
|
||||||
= PlanJSON | PlanText
|
= PlanJSON | PlanText
|
||||||
deriving Eq
|
|
||||||
|
|
||||||
-- | Convert MediaType to a Content-Type HTTP Header
|
-- | Convert MediaType to a Content-Type HTTP Header
|
||||||
toContentType :: MediaType -> Header
|
toContentType :: MediaType -> Header
|
||||||
toContentType ct = (hContentType, toMime ct <> charset)
|
toContentType ct = (hContentType, toMime ct <> charset)
|
||||||
where
|
where
|
||||||
charset = case ct of
|
charset = case ct of
|
||||||
MTNormal MTOctetStream -> mempty
|
MTOctetStream -> mempty
|
||||||
MTNormal (MTOther _) -> mempty
|
MTOther _ -> mempty
|
||||||
_ -> "; charset=utf-8"
|
_ -> "; charset=utf-8"
|
||||||
|
|
||||||
-- | Convert from MediaType to a ByteString representing the mime type
|
-- | Convert from MediaType to a ByteString representing the mime type
|
||||||
toMime :: MediaType -> ByteString
|
toMime :: MediaType -> ByteString
|
||||||
toMime (MTNormal x) = toMimeNormal x
|
toMime MTApplicationJSON = "application/json"
|
||||||
|
toMime MTGeoJSON = "application/geo+json"
|
||||||
|
toMime MTTextCSV = "text/csv"
|
||||||
|
toMime MTTextPlain = "text/plain"
|
||||||
|
toMime MTTextXML = "text/xml"
|
||||||
|
toMime MTOpenAPI = "application/openapi+json"
|
||||||
|
toMime MTSingularJSON = "application/vnd.pgrst.object+json"
|
||||||
|
toMime MTUrlEncoded = "application/x-www-form-urlencoded"
|
||||||
|
toMime MTOctetStream = "application/octet-stream"
|
||||||
|
toMime MTAny = "*/*"
|
||||||
|
toMime (MTOther ct) = ct
|
||||||
toMime (MTPlan (MTPlanAttrs mt fmt opts)) =
|
toMime (MTPlan (MTPlanAttrs mt fmt opts)) =
|
||||||
"application/vnd.pgrst.plan+" <> toMimePlanFormat fmt <>
|
"application/vnd.pgrst.plan+" <> toMimePlanFormat fmt <>
|
||||||
(if isNothing mt then mempty else "; for=\"" <> toMimeNormal (fromJust mt) <> "\"") <>
|
(if isNothing mt then mempty else "; for=\"" <> toMime (fromJust mt) <> "\"") <>
|
||||||
(if null opts then mempty else "; options=" <> BS.intercalate "|" (toMimePlanOption <$> opts))
|
(if null opts then mempty else "; options=" <> BS.intercalate "|" (toMimePlanOption <$> opts))
|
||||||
|
|
||||||
toMimeNormal :: NormalMedia -> ByteString
|
|
||||||
toMimeNormal = \case
|
|
||||||
MTApplicationJSON -> "application/json"
|
|
||||||
MTGeoJSON -> "application/geo+json"
|
|
||||||
MTTextCSV -> "text/csv"
|
|
||||||
MTTextPlain -> "text/plain"
|
|
||||||
MTTextXML -> "text/xml"
|
|
||||||
MTOpenAPI -> "application/openapi+json"
|
|
||||||
MTSingularJSON -> "application/vnd.pgrst.object+json"
|
|
||||||
MTUrlEncoded -> "application/x-www-form-urlencoded"
|
|
||||||
MTOctetStream -> "application/octet-stream"
|
|
||||||
MTAny -> "*/*"
|
|
||||||
(MTOther ct) -> ct
|
|
||||||
|
|
||||||
toMimePlanOption :: MTPlanOption -> ByteString
|
toMimePlanOption :: MTPlanOption -> ByteString
|
||||||
toMimePlanOption = \case
|
toMimePlanOption PlanAnalyze = "analyze"
|
||||||
PlanAnalyze -> "analyze"
|
toMimePlanOption PlanVerbose = "verbose"
|
||||||
PlanVerbose -> "verbose"
|
toMimePlanOption PlanSettings = "settings"
|
||||||
PlanSettings -> "settings"
|
toMimePlanOption PlanBuffers = "buffers"
|
||||||
PlanBuffers -> "buffers"
|
toMimePlanOption PlanWAL = "wal"
|
||||||
PlanWAL -> "wal"
|
|
||||||
|
|
||||||
toMimePlanFormat :: MTPlanFormat -> ByteString
|
toMimePlanFormat :: MTPlanFormat -> ByteString
|
||||||
toMimePlanFormat PlanJSON = "json"
|
toMimePlanFormat PlanJSON = "json"
|
||||||
toMimePlanFormat PlanText = "text"
|
toMimePlanFormat PlanText = "text"
|
||||||
|
|
||||||
-- | Convert from ByteString to MediaType.
|
|
||||||
--
|
|
||||||
-- >>> decodeMediaType "application/json"
|
|
||||||
-- MTNormal MTApplicationJSON
|
|
||||||
--
|
|
||||||
-- >>> decodeMediaType "application/vnd.pgrst.plan;"
|
|
||||||
-- MTPlan (MTPlanAttrs Nothing PlanText [])
|
|
||||||
--
|
|
||||||
-- >>> decodeMediaType "application/vnd.pgrst.plan;for=\"application/json\""
|
|
||||||
-- MTPlan (MTPlanAttrs (Just MTApplicationJSON) PlanText [])
|
|
||||||
--
|
|
||||||
-- >>> decodeMediaType "application/vnd.pgrst.plan;for=\"text/csv\""
|
|
||||||
-- MTPlan (MTPlanAttrs (Just MTTextCSV) PlanText [])
|
|
||||||
--
|
|
||||||
-- A plan media type inside "for" shouldn't recurse
|
|
||||||
--
|
|
||||||
-- >>> decodeMediaType "application/vnd.pgrst.plan;for=\"application/vnd.pgrst.plan\""
|
|
||||||
-- MTPlan (MTPlanAttrs (Just (MTOther "application/vnd.pgrst.plan")) PlanText [])
|
|
||||||
decodeMediaType :: BS.ByteString -> MediaType
|
|
||||||
decodeMediaType bs =
|
|
||||||
case BS.split (BS.c2w ';') bs of
|
|
||||||
"application/vnd.pgrst.plan":rest -> getPlan PlanText rest
|
|
||||||
"application/vnd.pgrst.plan+text":rest -> getPlan PlanText rest
|
|
||||||
"application/vnd.pgrst.plan+json":rest -> getPlan PlanJSON rest
|
|
||||||
mt -> MTNormal $ decodeNormalMediaType mt
|
|
||||||
where
|
|
||||||
getPlan fmt rest =
|
|
||||||
let
|
|
||||||
opts = BS.split (BS.c2w '|') $ fromMaybe mempty (BS.stripPrefix "options=" =<< find (BS.isPrefixOf "options=") rest)
|
|
||||||
inOpts str = str `elem` opts
|
|
||||||
mtFor = decodeNormalMediaType . L.singleton . dropAround (== BS.c2w '"') <$> (BS.stripPrefix "for=" =<< find (BS.isPrefixOf "for=") rest)
|
|
||||||
dropAround p = BS.dropWhile p . BS.dropWhileEnd p in
|
|
||||||
MTPlan $ MTPlanAttrs mtFor fmt $
|
|
||||||
[PlanAnalyze | inOpts "analyze" ] ++
|
|
||||||
[PlanVerbose | inOpts "verbose" ] ++
|
|
||||||
[PlanSettings | inOpts "settings"] ++
|
|
||||||
[PlanBuffers | inOpts "buffers" ] ++
|
|
||||||
[PlanWAL | inOpts "wal" ]
|
|
||||||
|
|
||||||
-- | Convert from ByteString to MediaType. Warning: discards MIME parameters
|
-- | Convert from ByteString to MediaType. Warning: discards MIME parameters
|
||||||
decodeNormalMediaType :: [BS.ByteString] -> NormalMedia
|
decodeMediaType :: BS.ByteString -> MediaType
|
||||||
decodeNormalMediaType bs =
|
decodeMediaType mt =
|
||||||
case bs of
|
case BS.split (BS.c2w ';') mt of
|
||||||
"application/json":_ -> MTApplicationJSON
|
"application/json":_ -> MTApplicationJSON
|
||||||
"application/geo+json":_ -> MTGeoJSON
|
"application/geo+json":_ -> MTGeoJSON
|
||||||
"text/csv":_ -> MTTextCSV
|
"text/csv":_ -> MTTextCSV
|
||||||
@@ -160,12 +97,28 @@ decodeNormalMediaType bs =
|
|||||||
"application/vnd.pgrst.object":_ -> MTSingularJSON
|
"application/vnd.pgrst.object":_ -> MTSingularJSON
|
||||||
"application/x-www-form-urlencoded":_ -> MTUrlEncoded
|
"application/x-www-form-urlencoded":_ -> MTUrlEncoded
|
||||||
"application/octet-stream":_ -> MTOctetStream
|
"application/octet-stream":_ -> MTOctetStream
|
||||||
|
"application/vnd.pgrst.plan":rest -> getPlan PlanText rest
|
||||||
|
"application/vnd.pgrst.plan+text":rest -> getPlan PlanText rest
|
||||||
|
"application/vnd.pgrst.plan+json":rest -> getPlan PlanJSON rest
|
||||||
"*/*":_ -> MTAny
|
"*/*":_ -> MTAny
|
||||||
other:_ -> MTOther other
|
other:_ -> MTOther other
|
||||||
_ -> MTAny
|
_ -> MTAny
|
||||||
|
where
|
||||||
|
getPlan fmt rest =
|
||||||
|
let
|
||||||
|
opts = BS.split (BS.c2w '|') $ fromMaybe mempty (BS.stripPrefix "options=" =<< find (BS.isPrefixOf "options=") rest)
|
||||||
|
inOpts str = str `elem` opts
|
||||||
|
mtFor = decodeMediaType . dropAround (== BS.c2w '"') <$> (BS.stripPrefix "for=" =<< find (BS.isPrefixOf "for=") rest)
|
||||||
|
dropAround p = BS.dropWhile p . BS.dropWhileEnd p in
|
||||||
|
MTPlan $ MTPlanAttrs mtFor fmt $
|
||||||
|
[PlanAnalyze | inOpts "analyze" ] ++
|
||||||
|
[PlanVerbose | inOpts "verbose" ] ++
|
||||||
|
[PlanSettings | inOpts "settings"] ++
|
||||||
|
[PlanBuffers | inOpts "buffers" ] ++
|
||||||
|
[PlanWAL | inOpts "wal" ]
|
||||||
|
|
||||||
getMediaType :: MediaType -> NormalMedia
|
getMediaType :: MediaType -> MediaType
|
||||||
getMediaType mt = case mt of
|
getMediaType mt = case mt of
|
||||||
MTPlan (MTPlanAttrs (Just mType) _ _) -> mType
|
MTPlan (MTPlanAttrs (Just mType) _ _) -> mType
|
||||||
MTPlan (MTPlanAttrs Nothing _ _) -> MTApplicationJSON
|
MTPlan (MTPlanAttrs Nothing _ _) -> MTApplicationJSON
|
||||||
MTNormal x -> x
|
other -> other
|
||||||
|
|||||||
+9
-10
@@ -45,8 +45,7 @@ import PostgREST.ApiRequest (Action (..),
|
|||||||
import PostgREST.Config (AppConfig (..))
|
import PostgREST.Config (AppConfig (..))
|
||||||
import PostgREST.Error (Error (..))
|
import PostgREST.Error (Error (..))
|
||||||
import PostgREST.MediaType (MTPlanAttrs (..),
|
import PostgREST.MediaType (MTPlanAttrs (..),
|
||||||
MediaType (..),
|
MediaType (..))
|
||||||
NormalMedia (..))
|
|
||||||
import PostgREST.Query.SqlFragment (sourceCTEName)
|
import PostgREST.Query.SqlFragment (sourceCTEName)
|
||||||
import PostgREST.RangeQuery (NonnegRange, allRange,
|
import PostgREST.RangeQuery (NonnegRange, allRange,
|
||||||
convertToLimitZeroRange,
|
convertToLimitZeroRange,
|
||||||
@@ -125,7 +124,7 @@ callReadPlan identifier conf sCache apiRequest invMethod = do
|
|||||||
let args = case (invMethod, iContentMediaType apiRequest) of
|
let args = case (invMethod, iContentMediaType apiRequest) of
|
||||||
(InvGet, _) -> jsonRpcParams proc qsParams'
|
(InvGet, _) -> jsonRpcParams proc qsParams'
|
||||||
(InvHead, _) -> jsonRpcParams proc qsParams'
|
(InvHead, _) -> jsonRpcParams proc qsParams'
|
||||||
(InvPost, MTNormal MTUrlEncoded) -> maybe mempty (jsonRpcParams proc . payArray) $ iPayload apiRequest
|
(InvPost, MTUrlEncoded) -> maybe mempty (jsonRpcParams proc . payArray) $ iPayload apiRequest
|
||||||
(InvPost, _) -> maybe mempty payRaw $ iPayload apiRequest
|
(InvPost, _) -> maybe mempty payRaw $ iPayload apiRequest
|
||||||
txMode = case (invMethod, pdVolatility) of
|
txMode = case (invMethod, pdVolatility) of
|
||||||
(InvGet, _) -> SQL.Read
|
(InvGet, _) -> SQL.Read
|
||||||
@@ -168,11 +167,11 @@ findProc qi argumentsKeys paramsAsSingleObject allProcs contentMediaType isInvPo
|
|||||||
-- If the function is called with post and has a single unnamed parameter
|
-- If the function is called with post and has a single unnamed parameter
|
||||||
-- it can be called depending on content type and the parameter type
|
-- it can be called depending on content type and the parameter type
|
||||||
hasSingleUnnamedParam Function{pdParams=[RoutineParam{ppType}]} = isInvPost && case (contentMediaType, ppType) of
|
hasSingleUnnamedParam Function{pdParams=[RoutineParam{ppType}]} = isInvPost && case (contentMediaType, ppType) of
|
||||||
(MTNormal MTApplicationJSON, "json") -> True
|
(MTApplicationJSON, "json") -> True
|
||||||
(MTNormal MTApplicationJSON, "jsonb") -> True
|
(MTApplicationJSON, "jsonb") -> True
|
||||||
(MTNormal MTTextPlain, "text") -> True
|
(MTTextPlain, "text") -> True
|
||||||
(MTNormal MTTextXML, "xml") -> True
|
(MTTextXML, "xml") -> True
|
||||||
(MTNormal MTOctetStream, "bytea") -> True
|
(MTOctetStream, "bytea") -> True
|
||||||
_ -> False
|
_ -> False
|
||||||
hasSingleUnnamedParam _ = False
|
hasSingleUnnamedParam _ = False
|
||||||
matchesParams proc =
|
matchesParams proc =
|
||||||
@@ -185,7 +184,7 @@ findProc qi argumentsKeys paramsAsSingleObject allProcs contentMediaType isInvPo
|
|||||||
then length params == 1 && (firstType == Just "json" || firstType == Just "jsonb")
|
then length params == 1 && (firstType == Just "json" || firstType == Just "jsonb")
|
||||||
-- If the function has no parameters, the arguments keys must be empty as well
|
-- If the function has no parameters, the arguments keys must be empty as well
|
||||||
else if null params
|
else if null params
|
||||||
then null argumentsKeys && not (isInvPost && contentMediaType `elem` [MTNormal MTOctetStream, MTNormal MTTextPlain, MTNormal MTTextXML])
|
then null argumentsKeys && not (isInvPost && contentMediaType `elem` [MTOctetStream, MTTextPlain, MTTextXML])
|
||||||
-- A function has optional and required parameters. Optional parameters have a default value and
|
-- A function has optional and required parameters. Optional parameters have a default value and
|
||||||
-- don't require arguments for the function to be executed, required parameters must have an argument present.
|
-- don't require arguments for the function to be executed, required parameters must have an argument present.
|
||||||
else case L.partition ppReq params of
|
else case L.partition ppReq params of
|
||||||
@@ -633,7 +632,7 @@ binaryField AppConfig{configRawMediaTypes} acceptMediaType proc rpTree
|
|||||||
| otherwise =
|
| otherwise =
|
||||||
Right Nothing
|
Right Nothing
|
||||||
where
|
where
|
||||||
isRawMediaType = acceptMediaType `elem` configRawMediaTypes `L.union` [MTNormal MTOctetStream, MTNormal MTTextPlain, MTNormal MTTextXML] || isRawPlan acceptMediaType
|
isRawMediaType = acceptMediaType `elem` configRawMediaTypes `L.union` [MTOctetStream, MTTextPlain, MTTextXML] || isRawPlan acceptMediaType
|
||||||
isRawPlan mt = case mt of
|
isRawPlan mt = case mt of
|
||||||
MTPlan (MTPlanAttrs (Just MTOctetStream) _ _) -> True
|
MTPlan (MTPlanAttrs (Just MTOctetStream) _ _) -> True
|
||||||
MTPlan (MTPlanAttrs (Just MTTextPlain) _ _) -> True
|
MTPlan (MTPlanAttrs (Just MTTextPlain) _ _) -> True
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ import PostgREST.Config (AppConfig (..),
|
|||||||
import PostgREST.Config.PgVersion (PgVersion (..),
|
import PostgREST.Config.PgVersion (PgVersion (..),
|
||||||
pgVersion140)
|
pgVersion140)
|
||||||
import PostgREST.Error (Error)
|
import PostgREST.Error (Error)
|
||||||
import PostgREST.MediaType (MediaType (..),
|
import PostgREST.MediaType (MediaType (..))
|
||||||
NormalMedia (..))
|
|
||||||
import PostgREST.Plan (CallReadPlan (..),
|
import PostgREST.Plan (CallReadPlan (..),
|
||||||
MutateReadPlan (..),
|
MutateReadPlan (..),
|
||||||
WrappedReadPlan (..))
|
WrappedReadPlan (..))
|
||||||
@@ -208,7 +207,7 @@ writeQuery MutateReadPlan{mrReadPlan, mrMutatePlan} apiReq@ApiRequest{iPreferenc
|
|||||||
failNotSingular :: MediaType -> ResultSet -> DbHandler ()
|
failNotSingular :: MediaType -> ResultSet -> DbHandler ()
|
||||||
failNotSingular _ RSPlan{} = pure ()
|
failNotSingular _ RSPlan{} = pure ()
|
||||||
failNotSingular mediaType RSStandard{rsQueryTotal=queryTotal} =
|
failNotSingular mediaType RSStandard{rsQueryTotal=queryTotal} =
|
||||||
when (mediaType == MTNormal MTSingularJSON && queryTotal /= 1) $ do
|
when (mediaType == MTSingularJSON && queryTotal /= 1) $ do
|
||||||
lift SQL.condemn
|
lift SQL.condemn
|
||||||
throwError $ Error.singularityError queryTotal
|
throwError $ Error.singularityError queryTotal
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import PostgREST.ApiRequest.Preferences
|
|||||||
import PostgREST.MediaType (MTPlanAttrs (..),
|
import PostgREST.MediaType (MTPlanAttrs (..),
|
||||||
MTPlanFormat (..),
|
MTPlanFormat (..),
|
||||||
MediaType (..),
|
MediaType (..),
|
||||||
NormalMedia (..),
|
|
||||||
getMediaType)
|
getMediaType)
|
||||||
import PostgREST.Query.SqlFragment
|
import PostgREST.Query.SqlFragment
|
||||||
import PostgREST.SchemaCache.Identifiers (FieldName)
|
import PostgREST.SchemaCache.Identifiers (FieldName)
|
||||||
@@ -190,7 +189,7 @@ standardRow noLocation =
|
|||||||
mtSnippet :: MediaType -> SQL.Snippet -> SQL.Snippet
|
mtSnippet :: MediaType -> SQL.Snippet -> SQL.Snippet
|
||||||
mtSnippet mediaType snippet = case mediaType of
|
mtSnippet mediaType snippet = case mediaType of
|
||||||
MTPlan (MTPlanAttrs _ fmt opts) -> explainF fmt opts snippet
|
MTPlan (MTPlanAttrs _ fmt opts) -> explainF fmt opts snippet
|
||||||
MTNormal _ -> snippet
|
_ -> snippet
|
||||||
|
|
||||||
-- | We use rowList because when doing EXPLAIN (FORMAT TEXT), the result comes as many rows. FORMAT JSON comes as one.
|
-- | We use rowList because when doing EXPLAIN (FORMAT TEXT), the result comes as many rows. FORMAT JSON comes as one.
|
||||||
planRow :: HD.Result ResultSet
|
planRow :: HD.Result ResultSet
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ import PostgREST.ApiRequest.Preferences (PreferRepresentation (..),
|
|||||||
toAppliedHeader)
|
toAppliedHeader)
|
||||||
import PostgREST.ApiRequest.QueryParams (QueryParams (..))
|
import PostgREST.ApiRequest.QueryParams (QueryParams (..))
|
||||||
import PostgREST.Config (AppConfig (..))
|
import PostgREST.Config (AppConfig (..))
|
||||||
import PostgREST.MediaType (MediaType (..),
|
import PostgREST.MediaType (MediaType (..))
|
||||||
NormalMedia (..))
|
|
||||||
import PostgREST.Plan (MutateReadPlan (..))
|
import PostgREST.Plan (MutateReadPlan (..))
|
||||||
import PostgREST.Plan.MutatePlan (MutatePlan (..))
|
import PostgREST.Plan.MutatePlan (MutatePlan (..))
|
||||||
import PostgREST.Query.Statements (ResultSet (..))
|
import PostgREST.Query.Statements (ResultSet (..))
|
||||||
@@ -227,7 +226,7 @@ invokeResponse invMethod proc ctxApiRequest@ApiRequest{..} resultSet = case resu
|
|||||||
openApiResponse :: Bool -> Maybe (TablesMap, RoutineMap, Maybe Text) -> AppConfig -> SchemaCache -> Schema -> Bool -> Wai.Response
|
openApiResponse :: Bool -> Maybe (TablesMap, RoutineMap, Maybe Text) -> AppConfig -> SchemaCache -> Schema -> Bool -> Wai.Response
|
||||||
openApiResponse headersOnly body conf sCache schema negotiatedByProfile =
|
openApiResponse headersOnly body conf sCache schema negotiatedByProfile =
|
||||||
Wai.responseLBS HTTP.status200
|
Wai.responseLBS HTTP.status200
|
||||||
(MediaType.toContentType (MTNormal MTOpenAPI) : maybeToList (profileHeader schema negotiatedByProfile))
|
(MediaType.toContentType MTOpenAPI : maybeToList (profileHeader schema negotiatedByProfile))
|
||||||
(maybe mempty (\(x, y, z) -> if headersOnly then mempty else OpenAPI.encode conf sCache x y z) body)
|
(maybe mempty (\(x, y, z) -> if headersOnly then mempty else OpenAPI.encode conf sCache x y z) body)
|
||||||
|
|
||||||
-- | Response with headers and status overridden from GUCs.
|
-- | Response with headers and status overridden from GUCs.
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ makeProcPathItem pd = ("/rpc/" ++ toS (pdName pd), pe)
|
|||||||
& summary .~ pSum
|
& summary .~ pSum
|
||||||
& description .~ mfilter (/="") pDesc
|
& description .~ mfilter (/="") pDesc
|
||||||
& tags .~ Set.fromList ["(rpc) " <> pdName pd]
|
& tags .~ Set.fromList ["(rpc) " <> pdName pd]
|
||||||
& produces ?~ makeMimeList [MTNormal MTApplicationJSON, MTNormal MTSingularJSON]
|
& produces ?~ makeMimeList [MTApplicationJSON, MTSingularJSON]
|
||||||
& at 200 ?~ "OK"
|
& at 200 ?~ "OK"
|
||||||
getOp = procOp
|
getOp = procOp
|
||||||
& parameters .~ makeProcGetParams (pdParams pd)
|
& parameters .~ makeProcGetParams (pdParams pd)
|
||||||
@@ -367,7 +367,7 @@ makeRootPathItem = ("/", p)
|
|||||||
getOp = (mempty :: Operation)
|
getOp = (mempty :: Operation)
|
||||||
& tags .~ Set.fromList ["Introspection"]
|
& tags .~ Set.fromList ["Introspection"]
|
||||||
& summary ?~ "OpenAPI description (this document)"
|
& summary ?~ "OpenAPI description (this document)"
|
||||||
& produces ?~ makeMimeList [MTNormal MTOpenAPI, MTNormal MTApplicationJSON]
|
& produces ?~ makeMimeList [MTOpenAPI, MTApplicationJSON]
|
||||||
& at 200 ?~ "OK"
|
& at 200 ?~ "OK"
|
||||||
pr = (mempty :: PathItem) & get ?~ getOp
|
pr = (mempty :: PathItem) & get ?~ getOp
|
||||||
p = pr
|
p = pr
|
||||||
@@ -407,8 +407,8 @@ postgrestSpec rels pds ti (s, h, p, b) sd allowSecurityDef = (mempty :: Swagger)
|
|||||||
& definitions .~ fromList (makeTableDef rels <$> ti)
|
& definitions .~ fromList (makeTableDef rels <$> ti)
|
||||||
& parameters .~ fromList (makeParamDefs ti)
|
& parameters .~ fromList (makeParamDefs ti)
|
||||||
& paths .~ makePathItems pds ti
|
& paths .~ makePathItems pds ti
|
||||||
& produces .~ makeMimeList mediaTypes
|
& produces .~ makeMimeList [MTApplicationJSON, MTSingularJSON, MTTextCSV]
|
||||||
& consumes .~ makeMimeList mediaTypes
|
& consumes .~ makeMimeList [MTApplicationJSON, MTSingularJSON, MTTextCSV]
|
||||||
& securityDefinitions .~ makeSecurityDefinitions securityDefName allowSecurityDef
|
& securityDefinitions .~ makeSecurityDefinitions securityDefName allowSecurityDef
|
||||||
& security .~ [SecurityRequirement (fromList [(securityDefName, [])]) | allowSecurityDef]
|
& security .~ [SecurityRequirement (fromList [(securityDefName, [])]) | allowSecurityDef]
|
||||||
where
|
where
|
||||||
@@ -417,7 +417,6 @@ postgrestSpec rels pds ti (s, h, p, b) sd allowSecurityDef = (mempty :: Swagger)
|
|||||||
securityDefName = "JWT"
|
securityDefName = "JWT"
|
||||||
(dTitle, dDesc) = fmap fst &&& fmap (T.dropWhile (=='\n') . snd) $
|
(dTitle, dDesc) = fmap fst &&& fmap (T.dropWhile (=='\n') . snd) $
|
||||||
T.breakOn "\n" <$> sd
|
T.breakOn "\n" <$> sd
|
||||||
mediaTypes = [MTNormal MTApplicationJSON, MTNormal MTSingularJSON, MTNormal MTTextCSV]
|
|
||||||
|
|
||||||
pickProxy :: Maybe Text -> Maybe Proxy
|
pickProxy :: Maybe Text -> Maybe Proxy
|
||||||
pickProxy proxy
|
pickProxy proxy
|
||||||
|
|||||||
@@ -16,5 +16,4 @@ main =
|
|||||||
, "src/PostgREST/ApiRequest/Preferences.hs"
|
, "src/PostgREST/ApiRequest/Preferences.hs"
|
||||||
, "src/PostgREST/ApiRequest/QueryParams.hs"
|
, "src/PostgREST/ApiRequest/QueryParams.hs"
|
||||||
, "src/PostgREST/Error.hs"
|
, "src/PostgREST/Error.hs"
|
||||||
, "src/PostgREST/MediaType.hs"
|
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ import PostgREST.Config (AppConfig (..),
|
|||||||
LogLevel (..),
|
LogLevel (..),
|
||||||
OpenAPIMode (..),
|
OpenAPIMode (..),
|
||||||
parseSecret)
|
parseSecret)
|
||||||
import PostgREST.MediaType (MediaType (..),
|
import PostgREST.MediaType (MediaType (..))
|
||||||
NormalMedia (..))
|
|
||||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
|
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
|
||||||
import Protolude hiding (get, toS)
|
import Protolude hiding (get, toS)
|
||||||
import Protolude.Conv (toS)
|
import Protolude.Conv (toS)
|
||||||
@@ -197,7 +196,7 @@ testCfgRootSpec :: AppConfig
|
|||||||
testCfgRootSpec = baseCfg { configDbRootSpec = Just $ QualifiedIdentifier mempty "root"}
|
testCfgRootSpec = baseCfg { configDbRootSpec = Just $ QualifiedIdentifier mempty "root"}
|
||||||
|
|
||||||
testCfgHtmlRawOutput :: AppConfig
|
testCfgHtmlRawOutput :: AppConfig
|
||||||
testCfgHtmlRawOutput = baseCfg { configRawMediaTypes = [MTNormal $ MTOther "text/html"] }
|
testCfgHtmlRawOutput = baseCfg { configRawMediaTypes = [MTOther "text/html"] }
|
||||||
|
|
||||||
testCfgResponseHeaders :: AppConfig
|
testCfgResponseHeaders :: AppConfig
|
||||||
testCfgResponseHeaders = baseCfg { configDbPreRequest = Just $ QualifiedIdentifier mempty "custom_headers" }
|
testCfgResponseHeaders = baseCfg { configDbPreRequest = Just $ QualifiedIdentifier mempty "custom_headers" }
|
||||||
|
|||||||
Reference in New Issue
Block a user