From 01c23a81243554b458d315b23fca04e6349df6e0 Mon Sep 17 00:00:00 2001 From: Joel Jakobsson Date: Mon, 7 Jul 2025 17:26:51 +0200 Subject: [PATCH] fix(openapi): respect function volatility for GET methods The OpenAPI specification was incorrectly exposing GET methods for VOLATILE functions, even though such functions properly reject GET requests at runtime with "405 Method Not Allowed". This created a mismatch between the advertised API specification and the actual runtime behavior. VOLATILE functions should only be callable via POST since they may have side effects, while STABLE and IMMUTABLE functions can safely be called via GET since they don't modify database state. Fix by checking the pdVolatility field in makeProcPathItem() and only including GET methods in the OpenAPI PathItem for non-volatile functions. The runtime behavior was already correct; this fixes only the OpenAPI documentation generation. --- CHANGELOG.md | 1 + src/PostgREST/Response/OpenAPI.hs | 9 ++++---- test/spec/Feature/OpenApi/OpenApiSpec.hs | 27 ++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60e7dd06a..1087bff91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Fix OpenAPI broken docs link by @taimoorzaeem in #4080 +- Fix OpenAPI specification incorrectly exposing GET methods for volatile functions by @joelonsql in #4174 ## [13.0.4] - 2025-06-17 diff --git a/src/PostgREST/Response/OpenAPI.hs b/src/PostgREST/Response/OpenAPI.hs index fe40e3c0f..9ca526932 100644 --- a/src/PostgREST/Response/OpenAPI.hs +++ b/src/PostgREST/Response/OpenAPI.hs @@ -30,7 +30,8 @@ import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..)) import PostgREST.SchemaCache.Relationship (Cardinality (..), Relationship (..), RelationshipsMap) -import PostgREST.SchemaCache.Routine (Routine (..), +import PostgREST.SchemaCache.Routine (FuncVolatility (..), + Routine (..), RoutineParam (..)) import PostgREST.SchemaCache.Table (Column (..), Table (..), TablesMap, @@ -355,9 +356,9 @@ makeProcPathItem pd = ("/rpc/" ++ toS (pdName pd), pe) & parameters .~ makeProcGetParams (pdParams pd) postOp = procOp & parameters .~ makeProcPostParams pd - pe = (mempty :: PathItem) - & get ?~ getOp - & post ?~ postOp + pe = case pdVolatility pd of + Volatile -> (mempty :: PathItem) & post ?~ postOp + _ -> (mempty :: PathItem) & get ?~ getOp & post ?~ postOp makeRootPathItem :: (FilePath, PathItem) makeRootPathItem = ("/", p) diff --git a/test/spec/Feature/OpenApi/OpenApiSpec.hs b/test/spec/Feature/OpenApi/OpenApiSpec.hs index fbe227a32..c035bbe7b 100644 --- a/test/spec/Feature/OpenApi/OpenApiSpec.hs +++ b/test/spec/Feature/OpenApi/OpenApiSpec.hs @@ -1058,6 +1058,33 @@ spec = describe "OpenAPI" $ do } |] + it "only includes POST method for volatile functions" $ do + r <- simpleBody <$> get "/" + let volatileGet = r ^? key "paths" . key "/rpc/reset_table" . key "get" + volatilePost = r ^? key "paths" . key "/rpc/reset_table" . key "post" + + liftIO $ do + volatileGet `shouldBe` Nothing + volatilePost `shouldNotBe` Nothing + + it "includes GET and POST methods for stable functions" $ do + r <- simpleBody <$> get "/" + let stableGet = r ^? key "paths" . key "/rpc/getallusers" . key "get" + stablePost = r ^? key "paths" . key "/rpc/getallusers" . key "post" + + liftIO $ do + stableGet `shouldNotBe` Nothing + stablePost `shouldNotBe` Nothing + + it "includes GET and POST methods for immutable functions" $ do + r <- simpleBody <$> get "/" + let immutableGet = r ^? key "paths" . key "/rpc/jwt_test" . key "get" + immutablePost = r ^? key "paths" . key "/rpc/jwt_test" . key "post" + + liftIO $ do + immutableGet `shouldNotBe` Nothing + immutablePost `shouldNotBe` Nothing + describe "Security" $ it "does not include security or security definitions by default" $ do r <- simpleBody <$> get "/"