From 799daa755666abb0b834ff2cf4889a7bea574d6f Mon Sep 17 00:00:00 2001 From: Ezequiel Alvarez Date: Sat, 26 Mar 2022 11:16:35 -0300 Subject: [PATCH] fix: json/jsonb columns should not have type "string" in OpenAPI spec (#2203) * Switch to no type for json/jsonb --- CHANGELOG.md | 1 + src/PostgREST/OpenAPI.hs | 34 +++++++++++++----------- test/io/test_io.py | 10 ++++--- test/spec/Feature/OpenApi/OpenApiSpec.hs | 34 +++++++++++++++++++++--- test/spec/fixtures/schema.sql | 4 ++- 5 files changed, 58 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9b2d217e..397427bf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed + - #2165, Fix json/jsonb columns should not have type in OpenAPI spec - #2020, Execute deferred constraint triggers when using `Prefer: tx=rollback` - @wolfgangwalther - #2058, Return 204 No Content without Content-Type for PUT - @wolfgangwalther - #2077, Fix `is` not working with upper or mixed case values like `NULL, TrUe, FaLsE` - @steve-chavez diff --git a/src/PostgREST/OpenAPI.hs b/src/PostgREST/OpenAPI.hs index cfdaae5c2..50e932466 100644 --- a/src/PostgREST/OpenAPI.hs +++ b/src/PostgREST/OpenAPI.hs @@ -55,24 +55,26 @@ encode conf dbStructure tables procs schemaDescription = makeMimeList :: [ContentType] -> MimeList makeMimeList cs = MimeList $ fmap (fromString . BS.unpack . toMime) cs -toSwaggerType :: Text -> SwaggerType t -toSwaggerType "character varying" = SwaggerString -toSwaggerType "character" = SwaggerString -toSwaggerType "text" = SwaggerString -toSwaggerType "boolean" = SwaggerBoolean -toSwaggerType "smallint" = SwaggerInteger -toSwaggerType "integer" = SwaggerInteger -toSwaggerType "bigint" = SwaggerInteger -toSwaggerType "numeric" = SwaggerNumber -toSwaggerType "real" = SwaggerNumber -toSwaggerType "double precision" = SwaggerNumber -toSwaggerType "ARRAY" = SwaggerArray -toSwaggerType _ = SwaggerString +toSwaggerType :: Text -> Maybe (SwaggerType t) +toSwaggerType "character varying" = Just SwaggerString +toSwaggerType "character" = Just SwaggerString +toSwaggerType "text" = Just SwaggerString +toSwaggerType "boolean" = Just SwaggerBoolean +toSwaggerType "smallint" = Just SwaggerInteger +toSwaggerType "integer" = Just SwaggerInteger +toSwaggerType "bigint" = Just SwaggerInteger +toSwaggerType "numeric" = Just SwaggerNumber +toSwaggerType "real" = Just SwaggerNumber +toSwaggerType "double precision" = Just SwaggerNumber +toSwaggerType "ARRAY" = Just SwaggerArray +toSwaggerType "json" = Nothing +toSwaggerType "jsonb" = Nothing +toSwaggerType _ = Just SwaggerString parseDefault :: Text -> Text -> Text parseDefault colType colDefault = case toSwaggerType colType of - SwaggerString -> wrapInQuotations $ case T.stripSuffix ("::" <> colType) colDefault of + Just SwaggerString -> wrapInQuotations $ case T.stripSuffix ("::" <> colType) colDefault of Just def -> T.dropAround (=='\'') def Nothing -> colDefault _ -> colDefault @@ -124,7 +126,7 @@ makeProperty rels pks c = (colName c, Inline s) & enum_ .~ e & format ?~ colType c & maxLength .~ (fromIntegral <$> colMaxLen c) - & type_ ?~ toSwaggerType (colType c) + & type_ .~ toSwaggerType (colType c) makeProcSchema :: ProcDescription -> Schema makeProcSchema pd = @@ -138,7 +140,7 @@ makeProcProperty :: ProcParam -> (Text, Referenced Schema) makeProcProperty (ProcParam n t _ _) = (n, Inline s) where s = (mempty :: Schema) - & type_ ?~ toSwaggerType t + & type_ .~ toSwaggerType t & format ?~ t makePreferParam :: [Text] -> Param diff --git a/test/io/test_io.py b/test/io/test_io.py index dd5f43bb0..ece77c147 100644 --- a/test/io/test_io.py +++ b/test/io/test_io.py @@ -883,17 +883,19 @@ def test_admin_live_dependent_on_main_app(defaultenv): response = postgrest.admin.get("/live") assert response.status_code == 503 + @pytest.mark.parametrize("specialhostvalue", FIXTURES["specialhostvalues"]) def test_admin_works_with_host_special_values(specialhostvalue, defaultenv): "Should get a success from the admin live and ready endpoints when using special host values for the main app" with run(env=defaultenv, port=freeport(), host=specialhostvalue) as postgrest: - response = postgrest.admin.get("/live") - assert response.status_code == 200 + response = postgrest.admin.get("/live") + assert response.status_code == 200 + + response = postgrest.admin.get("/ready") + assert response.status_code == 200 - response = postgrest.admin.get("/ready") - assert response.status_code == 200 @pytest.mark.parametrize( "level, has_output", diff --git a/test/spec/Feature/OpenApi/OpenApiSpec.hs b/test/spec/Feature/OpenApi/OpenApiSpec.hs index 3b4a5a945..fe35310a4 100644 --- a/test/spec/Feature/OpenApi/OpenApiSpec.hs +++ b/test/spec/Feature/OpenApi/OpenApiSpec.hs @@ -430,6 +430,34 @@ spec actualPgVersion = describe "OpenAPI" $ do } |] + it "json to any" $ do + r <- simpleBody <$> get "/" + + let types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_json" + + liftIO $ + + types `shouldBe` Just + [aesonQQ| + { + "format": "json" + } + |] + + it "jsonb to any" $ do + r <- simpleBody <$> get "/" + + let types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_jsonb" + + liftIO $ + + types `shouldBe` Just + [aesonQQ| + { + "format": "jsonb" + } + |] + describe "Detects default values" $ do it "text" $ do @@ -548,12 +576,10 @@ spec actualPgVersion = describe "OpenAPI" $ do "type": "integer" }, "json": { - "format": "json", - "type": "string" + "format": "json" }, "jsonb": { - "format": "jsonb", - "type": "string" + "format": "jsonb" } }, "type": "object", diff --git a/test/spec/fixtures/schema.sql b/test/spec/fixtures/schema.sql index e2565855b..e52b56348 100644 --- a/test/spec/fixtures/schema.sql +++ b/test/spec/fixtures/schema.sql @@ -1807,7 +1807,9 @@ CREATE TABLE test.openapi_types( "a_bigint" bigint, "a_numeric" numeric, "a_real" real, - "a_double_precision" double precision + "a_double_precision" double precision, + "a_json" json, + "a_jsonb" jsonb ); CREATE TABLE test.openapi_defaults(