diff --git a/CHANGELOG.md b/CHANGELOG.md index 64ac8bfed1f..4d5a7b39081 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). + Can be replaced with custom media types - #1462, #1548, Removed `application/octet-stream`, `text/plain`, `text/xml` [builtin support for scalar results](https://postgrest.org/en/v11.1/references/api/resource_representation.html#scalar-function-response-format) - @steve-chavez + Can be replaced with custom media types + - #1462, #1548, Removed default `application/openapi+json` media type for [db-root-spec](https://postgrest.org/en/v11.1/references/configuration.html#db-root-spec) - @steve-chavez ## [11.1.0] - 2023-06-07 diff --git a/src/PostgREST/ApiRequest.hs b/src/PostgREST/ApiRequest.hs index 2e3313e130e..826d44021cf 100644 --- a/src/PostgREST/ApiRequest.hs +++ b/src/PostgREST/ApiRequest.hs @@ -15,7 +15,6 @@ module PostgREST.ApiRequest , Action(..) , Target(..) , Payload(..) - , PathInfo(..) , userApiRequest ) where @@ -127,7 +126,6 @@ data ApiRequest = ApiRequest { , iHeaders :: [(ByteString, ByteString)] -- ^ HTTP request headers , iCookies :: [(ByteString, ByteString)] -- ^ Request Cookies , iPath :: ByteString -- ^ Raw request path - , iPathInfo :: PathInfo -- ^ Cached info about the path , iMethod :: ByteString -- ^ Raw request method , iSchema :: Schema -- ^ The request schema. Can vary depending on profile headers. , iNegotiatedByProfile :: Bool -- ^ If schema was was chosen according to the profile spec https://www.w3.org/TR/dx-prof-conneg/ @@ -158,7 +156,6 @@ userApiRequest conf req reqBody = do , iHeaders = iHdrs , iCookies = iCkies , iPath = rawPathInfo req - , iPathInfo = pInfo , iMethod = method , iSchema = schema , iNegotiatedByProfile = negotiatedByProfile diff --git a/src/PostgREST/Plan.hs b/src/PostgREST/Plan.hs index f93a80d362c..8ce2873ce42 100644 --- a/src/PostgREST/Plan.hs +++ b/src/PostgREST/Plan.hs @@ -41,7 +41,6 @@ import PostgREST.ApiRequest (Action (..), ApiRequest (..), InvokeMethod (..), Mutation (..), - PathInfo (..), Payload (..)) import PostgREST.Config (AppConfig (..)) import PostgREST.Error (Error (..)) @@ -123,7 +122,7 @@ data InspectPlan = InspectPlan { wrappedReadPlan :: QualifiedIdentifier -> AppConfig -> SchemaCache -> ApiRequest -> Either Error WrappedReadPlan wrappedReadPlan identifier conf sCache apiRequest@ApiRequest{iPreferences=Preferences{..},..} = do rPlan <- readPlan identifier conf sCache apiRequest - mediaType <- mapLeft ApiRequestError $ negotiateContent conf iAction iPathInfo iAcceptMediaType + mediaType <- mapLeft ApiRequestError $ negotiateContent conf iAction iAcceptMediaType if not (null invalidPrefs) && preferHandling == Just Strict then Left $ ApiRequestError $ InvalidPreferences invalidPrefs else Right () return $ WrappedReadPlan rPlan SQL.Read (mediaToAggregate mediaType apiRequest) mediaType @@ -131,7 +130,7 @@ mutateReadPlan :: Mutation -> ApiRequest -> QualifiedIdentifier -> AppConfig -> mutateReadPlan mutation apiRequest@ApiRequest{iPreferences=Preferences{..},..} identifier conf sCache = do rPlan <- readPlan identifier conf sCache apiRequest mPlan <- mutatePlan mutation identifier apiRequest sCache rPlan - mediaType <- mapLeft ApiRequestError $ negotiateContent conf iAction iPathInfo iAcceptMediaType + mediaType <- mapLeft ApiRequestError $ negotiateContent conf iAction iAcceptMediaType if not (null invalidPrefs) && preferHandling == Just Strict then Left $ ApiRequestError $ InvalidPreferences invalidPrefs else Right () return $ MutateReadPlan rPlan mPlan SQL.Write (mediaToAggregate mediaType apiRequest) mediaType @@ -157,7 +156,7 @@ callReadPlan identifier conf sCache apiRequest@ApiRequest{iPreferences=Preferenc (InvPost, Routine.Immutable) -> SQL.Read (InvPost, Routine.Volatile) -> SQL.Write cPlan = callPlan proc apiRequest paramKeys args rPlan - mediaType <- mapLeft ApiRequestError $ negotiateContent conf iAction iPathInfo iAcceptMediaType + mediaType <- mapLeft ApiRequestError $ negotiateContent conf iAction iAcceptMediaType if not (null invalidPrefs) && preferHandling == Just Strict then Left $ ApiRequestError $ InvalidPreferences invalidPrefs else Right () return $ CallReadPlan rPlan cPlan txMode proc (mediaToAggregate mediaType apiRequest) mediaType where @@ -165,7 +164,7 @@ callReadPlan identifier conf sCache apiRequest@ApiRequest{iPreferences=Preferenc inspectPlan :: AppConfig -> ApiRequest -> Either Error InspectPlan inspectPlan conf apiRequest = do - mediaType <- mapLeft ApiRequestError $ negotiateContent conf (iAction apiRequest) (iPathInfo apiRequest) (iAcceptMediaType apiRequest) + mediaType <- mapLeft ApiRequestError $ negotiateContent conf (iAction apiRequest) (iAcceptMediaType apiRequest) return $ InspectPlan mediaType SQL.Read {-| @@ -851,29 +850,26 @@ mediaToAggregate mt apiReq@ApiRequest{iAction=act, iPreferences=Preferences{pref _ -> False -- | Do content negotiation. i.e. choose a media type based on the intersection of accepted/produced media types. -negotiateContent :: AppConfig -> Action -> PathInfo -> [MediaType] -> Either ApiRequestError MediaType -negotiateContent conf action path accepts = +negotiateContent :: AppConfig -> Action -> [MediaType] -> Either ApiRequestError MediaType +negotiateContent conf action accepts = case firstAcceptedPick of Just MTAny -> Right MTApplicationJSON -- by default(for */*) we respond with json Just mt -> Right mt Nothing -> Left . MediaTypeError $ map MediaType.toMime accepts where -- if there are multiple accepted media types, pick the first - firstAcceptedPick = listToMaybe $ L.intersect accepts $ producedMediaTypes conf action path + firstAcceptedPick = listToMaybe $ L.intersect accepts $ producedMediaTypes conf action -producedMediaTypes :: AppConfig -> Action -> PathInfo -> [MediaType] -producedMediaTypes conf action path = +producedMediaTypes :: AppConfig -> Action -> [MediaType] +producedMediaTypes conf action = case action of ActionRead _ -> defaultMediaTypes - ActionInvoke _ -> invokeMediaTypes + ActionInvoke _ -> defaultMediaTypes ActionInfo -> defaultMediaTypes ActionMutate _ -> defaultMediaTypes ActionInspect _ -> inspectMediaTypes where inspectMediaTypes = [MTOpenAPI, MTApplicationJSON, MTArrayJSONStrip, MTAny] - invokeMediaTypes = - defaultMediaTypes - ++ [MTOpenAPI | pathIsRootSpec path] defaultMediaTypes = [MTApplicationJSON, MTArrayJSONStrip, MTSingularJSON True, MTSingularJSON False, MTGeoJSON, MTTextCSV] ++ [MTPlan MTApplicationJSON PlanText mempty | configDbPlanEnabled conf] ++ [MTAny] diff --git a/test/spec/Feature/OpenApi/RootSpec.hs b/test/spec/Feature/OpenApi/RootSpec.hs index c450d464ab4..a1ab1d78bbd 100644 --- a/test/spec/Feature/OpenApi/RootSpec.hs +++ b/test/spec/Feature/OpenApi/RootSpec.hs @@ -3,7 +3,7 @@ module Feature.OpenApi.RootSpec where import Network.HTTP.Types import Network.Wai (Application) -import Test.Hspec +import Test.Hspec hiding (pendingWith) import Test.Hspec.Wai import Test.Hspec.Wai.JSON @@ -12,7 +12,8 @@ import Protolude hiding (get) spec :: SpecWith ((), Application) spec = describe "root spec function" $ do - it "accepts application/openapi+json" $ + it "accepts application/openapi+json" $ do + pendingWith "TBD" request methodGet "/" [("Accept","application/openapi+json")] "" `shouldRespondWith` [json|{