Revert "add: configs as json GUC for db-root-spec"
This reverts commit f34ca15e84.
This commit is contained in:
@@ -18,7 +18,6 @@ All notable changes to this project will be documented in this file. From versio
|
||||
- Add config `server-reuseport` to allow starting multiple PostgREST instances using the same port on supported platforms by @mkleczek in #4703, #4694
|
||||
- Make config `log-level` reloadable by @taimoorzaeem in #5113
|
||||
- Optimize schema cache domain type resolution by using `pg_basetype` on PostgreSQL 17+ by @joelonsql in #4567
|
||||
- When `db-root-spec` is used, a `request.root.configs` GUC will be available to build a complete custom OpenAPI response by @steve-chavez in #3029
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@@ -66,34 +66,24 @@ You can override the whole default response with a function result. To do this,
|
||||
|
||||
db-root-spec = "root"
|
||||
|
||||
When this function is called, the ``request.root.configs`` GUC contains a JSON object with the following keys:
|
||||
|
||||
* ``server_host`` (string)
|
||||
* ``server_port`` (string)
|
||||
* ``openapi_server_proxy_uri`` (string)
|
||||
* ``db_schemas`` (JSON array of strings)
|
||||
* ``version`` (string)
|
||||
|
||||
The root spec function can read this JSON and use its values when constructing the response:
|
||||
|
||||
.. code:: postgres
|
||||
|
||||
create or replace function root() returns json as $_$
|
||||
declare
|
||||
configs json := current_setting('request.root.configs', true)::json;
|
||||
openapi json = $$
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info":{
|
||||
"title":"Overridden",
|
||||
"description":"This is a my own API"
|
||||
}
|
||||
}
|
||||
$$;
|
||||
begin
|
||||
return json_build_object(
|
||||
'swagger', '2.0',
|
||||
'info', json_build_object(
|
||||
'title', 'Overridden',
|
||||
'description', 'This is my own API',
|
||||
'version', configs->>'version'
|
||||
)
|
||||
);
|
||||
return openapi;
|
||||
end
|
||||
$_$ language plpgsql;
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl http://localhost:3000
|
||||
@@ -106,7 +96,6 @@ The root spec function can read this JSON and use its values when constructing t
|
||||
"swagger": "2.0",
|
||||
"info":{
|
||||
"title":"Overridden",
|
||||
"description":"This is my own API",
|
||||
"version":"14.0.0"
|
||||
"description":"This is a my own API"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ import Protolude
|
||||
-}
|
||||
data ApiRequest = ApiRequest {
|
||||
iAction :: Action -- ^ Action on the resource
|
||||
, iIsRootRoutine :: Bool -- ^ If the request wants the root routine
|
||||
, iRange :: HM.HashMap Text NonnegRange -- ^ Requested range of rows within response
|
||||
, iTopLevelRange :: NonnegRange -- ^ Requested range of rows from the top level
|
||||
, iPayload :: Maybe Payload -- ^ Data sent by client and used for mutation actions
|
||||
@@ -77,7 +76,7 @@ data ApiRequest = ApiRequest {
|
||||
-- | Examines HTTP request and translates it into user intent.
|
||||
userApiRequest :: AppConfig -> Preferences.Preferences -> Request -> RequestBody -> Either ApiRequestError ApiRequest
|
||||
userApiRequest conf prefs req reqBody = do
|
||||
(resource, isRootRoutine) <- getResource conf $ pathInfo req
|
||||
resource <- getResource conf $ pathInfo req
|
||||
(schema, negotiatedByProfile) <- getSchema conf hdrs method
|
||||
act <- getAction resource schema method
|
||||
qPrms <- first QueryParamError $ QueryParams.parse (actIsInvokeSafe act) $ rawQueryString req
|
||||
@@ -95,7 +94,6 @@ userApiRequest conf prefs req reqBody = do
|
||||
, iCookies = iCkies
|
||||
, iPath = rawPathInfo req
|
||||
, iMethod = method
|
||||
, iIsRootRoutine = isRootRoutine
|
||||
, iSchema = schema
|
||||
, iNegotiatedByProfile = negotiatedByProfile
|
||||
, iAcceptMediaType = maybe [MTAny] (map MediaType.decodeMediaType . parseHttpAccept) $ lookupHeader "accept"
|
||||
@@ -118,16 +116,16 @@ userPreferences conf req timezones = Preferences.fromHeaders (configDbTxAllowOve
|
||||
userBearerAuth :: Request -> Maybe ByteString
|
||||
userBearerAuth req = extractBearerAuth =<< lookup hAuthorization (requestHeaders req)
|
||||
|
||||
getResource :: AppConfig -> [Text] -> Either ApiRequestError (Resource, Bool)
|
||||
getResource :: AppConfig -> [Text] -> Either ApiRequestError Resource
|
||||
getResource AppConfig{configOpenApiMode, configDbRootSpec} = \case
|
||||
[] ->
|
||||
case (configOpenApiMode,configDbRootSpec) of
|
||||
(OADisabled,_) -> Left OpenAPIDisabled
|
||||
(_, Just qi) -> Right (ResourceRoutine (qiName qi), True)
|
||||
(_, Nothing) -> Right (ResourceSchema, False)
|
||||
(_, Just qi) -> Right $ ResourceRoutine (qiName qi)
|
||||
(_, Nothing) -> Right ResourceSchema
|
||||
|
||||
[table] -> Right (ResourceRelation table, False)
|
||||
["rpc", pName] -> Right (ResourceRoutine pName , False)
|
||||
[table] -> Right $ ResourceRelation table
|
||||
["rpc", pName] -> Right $ ResourceRoutine pName
|
||||
_ -> Left InvalidResourcePath
|
||||
|
||||
getAction :: Resource -> Schema -> ByteString -> Either ApiRequestError Action
|
||||
|
||||
@@ -29,7 +29,6 @@ import PostgREST.Query.SqlFragment (escapeIdentList, fromQi,
|
||||
setConfigWithDynamicName)
|
||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
|
||||
import PostgREST.SchemaCache.Routine (Routine (..))
|
||||
import PostgREST.Version (prettyVersion)
|
||||
|
||||
import Protolude hiding (Handler)
|
||||
|
||||
@@ -39,7 +38,7 @@ txVarQuery dbActPlan AppConfig{..} AuthResult{..} ApiRequest{..} =
|
||||
-- To ensure `GRANT SET ON PARAMETER <superuser_setting> TO authenticator` works, the role settings must be set before the impersonated role.
|
||||
-- Otherwise the GRANT SET would have to be applied to the impersonated role. See https://github.com/PostgREST/postgrest/issues/3045
|
||||
"select " <> intercalateSnippet ", " (
|
||||
searchPathSql : roleSettingsSql ++ roleSql ++ claimsSql ++ [methodSql, pathSql] ++ headersSql ++ cookiesSql ++ timezoneSql ++ funcSettingsSql ++ appSettingsSql ++ rootSpecSettingsSql
|
||||
searchPathSql : roleSettingsSql ++ roleSql ++ claimsSql ++ [methodSql, pathSql] ++ headersSql ++ cookiesSql ++ timezoneSql ++ funcSettingsSql ++ appSettingsSql
|
||||
)
|
||||
where
|
||||
methodSql = setConfigWithConstantName ("request.method", iMethod)
|
||||
@@ -53,20 +52,6 @@ txVarQuery dbActPlan AppConfig{..} AuthResult{..} ApiRequest{..} =
|
||||
roleSql = [setConfigWithConstantName ("role", authRole)]
|
||||
roleSettingsSql = setConfigWithDynamicName <$> HM.toList (fromMaybe mempty $ HM.lookup authRole configRoleSettings)
|
||||
appSettingsSql = setConfigWithDynamicName . join bimap toUtf8 <$> configAppSettings
|
||||
rootSpecSettingsSql
|
||||
| iIsRootRoutine =
|
||||
[ setConfigWithConstantName
|
||||
( "request.root.configs"
|
||||
, LBS.toStrict $ JSON.encode $ JSON.object
|
||||
[ "server_host" JSON..= configServerHost
|
||||
, "server_port" JSON..= (show configServerPort :: Text)
|
||||
, "openapi_server_proxy_uri" JSON..= configOpenApiServerProxyUri
|
||||
, "db_schemas" JSON..= toList configDbSchemas
|
||||
, "version" JSON..= decodeUtf8 prettyVersion
|
||||
]
|
||||
)
|
||||
]
|
||||
| otherwise = mempty
|
||||
timezoneSql = maybe mempty (\(PreferTimezone tz) -> [setConfigWithConstantName ("timezone", tz)]) $ preferTimezone iPreferences
|
||||
funcSettingsSql = setConfigWithDynamicName . join bimap toUtf8 <$> funcSettings
|
||||
searchPathSql =
|
||||
|
||||
@@ -8,29 +8,19 @@ import Test.Hspec.Wai.JSON
|
||||
|
||||
import PostgREST.Config (AppConfig (..))
|
||||
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
|
||||
import PostgREST.Version (prettyVersion)
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
|
||||
spec :: SpecWithConfig
|
||||
spec withConfig = withConfig (baseCfg
|
||||
{ configDbRootSpec = Just $ QualifiedIdentifier mempty "root"
|
||||
, configDbSchemas = "test" :| ["v1"]
|
||||
, configOpenApiServerProxyUri = Just "https://example.com/base"
|
||||
}) $
|
||||
spec withConfig = withConfig (baseCfg { configDbRootSpec = Just $ QualifiedIdentifier mempty "root" }) $
|
||||
describe "root spec function" $ do
|
||||
it "accepts application/openapi+json" $ do
|
||||
request methodGet "/"
|
||||
[("Accept","application/openapi+json")] "" `shouldRespondWith`
|
||||
[json|{
|
||||
"swagger": "2.0",
|
||||
"info": {"title": "PostgREST API", "description": "This is a dynamic API generated by PostgREST"},
|
||||
"pgrst_server_host": "localhost",
|
||||
"pgrst_server_port": "3000",
|
||||
"pgrst_openapi_server_proxy_uri": "https://example.com/base",
|
||||
"pgrst_db_schemas": ["test", "v1"],
|
||||
"pgrst_version": #{decodeUtf8 prettyVersion}
|
||||
"info": {"title": "PostgREST API", "description": "This is a dynamic API generated by PostgREST"}
|
||||
}|]
|
||||
{ matchHeaders = ["Content-Type" <:> "application/openapi+json; charset=utf-8"] }
|
||||
|
||||
@@ -39,25 +29,6 @@ spec withConfig = withConfig (baseCfg
|
||||
[("Accept","application/json")] "" `shouldRespondWith`
|
||||
[json|{
|
||||
"swagger": "2.0",
|
||||
"info": {"title": "PostgREST API", "description": "This is a dynamic API generated by PostgREST"},
|
||||
"pgrst_server_host": "localhost",
|
||||
"pgrst_server_port": "3000",
|
||||
"pgrst_openapi_server_proxy_uri": "https://example.com/base",
|
||||
"pgrst_db_schemas": ["test", "v1"],
|
||||
"pgrst_version": #{decodeUtf8 prettyVersion}
|
||||
"info": {"title": "PostgREST API", "description": "This is a dynamic API generated by PostgREST"}
|
||||
}|]
|
||||
{ matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"] }
|
||||
|
||||
it "returns null GUCs on non-root paths" $ do
|
||||
request methodGet "/rpc/root"
|
||||
[("Accept","application/openapi+json")] "" `shouldRespondWith`
|
||||
[json|{
|
||||
"swagger": "2.0",
|
||||
"info": {"title": "PostgREST API", "description": "This is a dynamic API generated by PostgREST"},
|
||||
"pgrst_server_host": null,
|
||||
"pgrst_server_port": null,
|
||||
"pgrst_openapi_server_proxy_uri": null,
|
||||
"pgrst_db_schemas": null,
|
||||
"pgrst_version": null
|
||||
}|]
|
||||
{ matchHeaders = ["Content-Type" <:> "application/openapi+json; charset=utf-8"] }
|
||||
|
||||
Vendored
+11
-15
@@ -1866,22 +1866,18 @@ $$ language sql;
|
||||
|
||||
create or replace function root() returns "application/openapi+json" as $_$
|
||||
declare
|
||||
pgrst_config json := nullif(current_setting('request.root.configs', true), '')::json;
|
||||
openapi json = $$
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info":{
|
||||
"title":"PostgREST API",
|
||||
"description":"This is a dynamic API generated by PostgREST"
|
||||
}
|
||||
}
|
||||
$$;
|
||||
begin
|
||||
return (
|
||||
select json_build_object(
|
||||
'swagger', '2.0',
|
||||
'info', json_build_object(
|
||||
'title', 'PostgREST API',
|
||||
'description', 'This is a dynamic API generated by PostgREST'
|
||||
),
|
||||
'pgrst_server_host', pgrst_config->>'server_host',
|
||||
'pgrst_server_port', pgrst_config->>'server_port',
|
||||
'pgrst_openapi_server_proxy_uri', pgrst_config->>'openapi_server_proxy_uri',
|
||||
'pgrst_db_schemas', pgrst_config->'db_schemas',
|
||||
'pgrst_version', pgrst_config->>'version'
|
||||
)::json);
|
||||
end;
|
||||
return openapi;
|
||||
end
|
||||
$_$ language plpgsql;
|
||||
|
||||
create or replace function welcome() returns "text/plain" as $$
|
||||
|
||||
Reference in New Issue
Block a user