From 4ba6b1b30cbf1e41f9e60e5da74ba79a1c19ccdd Mon Sep 17 00:00:00 2001 From: Laurence Isla Date: Wed, 14 May 2025 19:55:48 -0500 Subject: [PATCH] feat: improve error response when the requested schema is invalid - It now shows the invalid schema in the "message" - The exposed schemas are now listed in the "hint" instead of the "message" --- CHANGELOG.md | 6 ++++++ src/PostgREST/ApiRequest.hs | 2 +- src/PostgREST/Error.hs | 5 +++-- test/spec/Feature/Query/MultipleSchemaSpec.hs | 14 +++++++------- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2ef12992..dacb8f981 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Added + +- Improve the `PGRST106` error when the requested schema is invalid by @laurenceisla in #4089 + + It now shows the invalid schema in the `message` field. + + The exposed schemas are now listed in the `hint` instead of the `message` field. + ## [13.0.6] - 2025-08-30 ### Fixed diff --git a/src/PostgREST/ApiRequest.hs b/src/PostgREST/ApiRequest.hs index 07222466c..0e2b11634 100644 --- a/src/PostgREST/ApiRequest.hs +++ b/src/PostgREST/ApiRequest.hs @@ -207,7 +207,7 @@ getAction resource schema method = getSchema :: AppConfig -> RequestHeaders -> ByteString -> Either ApiRequestError (Schema, Bool) getSchema AppConfig{configDbSchemas} hdrs method = do case profile of - Just p | p `notElem` configDbSchemas -> Left $ UnacceptableSchema $ toList configDbSchemas + Just p | p `notElem` configDbSchemas -> Left $ UnacceptableSchema p $ toList configDbSchemas | otherwise -> Right (p, True) Nothing -> Right (defaultSchema, length configDbSchemas /= 1) -- if we have many schemas, assume the default schema was negotiated where diff --git a/src/PostgREST/Error.hs b/src/PostgREST/Error.hs index 0fd2be2d5..1b03b78f0 100644 --- a/src/PostgREST/Error.hs +++ b/src/PostgREST/Error.hs @@ -86,7 +86,7 @@ data ApiRequestError | QueryParamError QPError | RelatedOrderNotToOne Text Text | UnacceptableFilter Text - | UnacceptableSchema [Text] + | UnacceptableSchema Text [Text] | UnsupportedMethod ByteString | GucHeadersError | GucStatusError @@ -194,7 +194,7 @@ instance ErrorBody ApiRequestError where message (InvalidBody errorMessage) = T.decodeUtf8 errorMessage message (InvalidRange _) = "Requested range not satisfiable" message InvalidFilters = "Filters must include all and only primary key columns with 'eq' operators" - message (UnacceptableSchema schemas) = "The schema must be one of the following: " <> T.intercalate ", " schemas + message (UnacceptableSchema sch _) = "Invalid schema: " <> sch message (MediaTypeError cts) = "None of these media types are available: " <> T.intercalate ", " (map T.decodeUtf8 cts) message (NotEmbedded resource) = "'" <> resource <> "' is not an embedded resource in this request" message GucHeadersError = "response.headers guc must be a JSON array composed of objects with a single key and a string value" @@ -234,6 +234,7 @@ instance ErrorBody ApiRequestError where -- HINT: Maybe JSON.Value hint (NotEmbedded resource) = Just $ JSON.String $ "Verify that '" <> resource <> "' is included in the 'select' query parameter." hint (PGRSTParseError raiseErr) = Just $ JSON.String $ pgrstParseErrorHint raiseErr + hint (UnacceptableSchema _ schemas) = Just $ JSON.String $ "Only the following schemas are exposed: " <> T.intercalate ", " schemas hint _ = Nothing diff --git a/test/spec/Feature/Query/MultipleSchemaSpec.hs b/test/spec/Feature/Query/MultipleSchemaSpec.hs index b52095bc3..4a94c5419 100644 --- a/test/spec/Feature/Query/MultipleSchemaSpec.hs +++ b/test/spec/Feature/Query/MultipleSchemaSpec.hs @@ -72,9 +72,9 @@ spec = , matchHeaders = [] } - it "fails trying to read table from unkown schema" $ - request methodGet "/parents" [("Accept-Profile", "unkown")] "" `shouldRespondWith` - [json|{"message":"The schema must be one of the following: v1, v2, SPECIAL \"@/\\#~_-","code":"PGRST106","details":null,"hint":null}|] + it "fails trying to read table from unknown schema" $ + request methodGet "/parents" [("Accept-Profile", "unknown")] "" `shouldRespondWith` + [json|{"message":"Invalid schema: unknown","code":"PGRST106","details":null,"hint":"Only the following schemas are exposed: v1, v2, SPECIAL \"@/\\#~_-"}|] { matchStatus = 406 } @@ -151,7 +151,7 @@ spec = request methodPost "/children" [("Content-Profile", "unknown")] [json|{"name": "child 4", "parent_id": 4}|] `shouldRespondWith` - [json|{"message":"The schema must be one of the following: v1, v2, SPECIAL \"@/\\#~_-","code":"PGRST106","details":null,"hint":null}|] + [json|{"message":"Invalid schema: unknown","code":"PGRST106","details":null,"hint":"Only the following schemas are exposed: v1, v2, SPECIAL \"@/\\#~_-"}|] { matchStatus = 406 } @@ -389,9 +389,9 @@ spec = let def = simpleBody r ^? key "definitions" . key "another_table" def `shouldBe` Nothing - it "fails trying to read definitions from unkown schema" $ - request methodGet "/" [("Accept-Profile", "unkown")] "" `shouldRespondWith` - [json|{"message":"The schema must be one of the following: v1, v2, SPECIAL \"@/\\#~_-","code":"PGRST106","details":null,"hint":null}|] + it "fails trying to read definitions from unknown schema" $ + request methodGet "/" [("Accept-Profile", "unknown")] "" `shouldRespondWith` + [json|{"message":"Invalid schema: unknown","code":"PGRST106","details":null,"hint":"Only the following schemas are exposed: v1, v2, SPECIAL \"@/\\#~_-"}|] { matchStatus = 406 }