Skip to content

Commit c3b6154

Browse files
committed
Fix schema for Maybe
1 parent e6a7a01 commit c3b6154

2 files changed

Lines changed: 15 additions & 16 deletions

File tree

src/Data/OpenApi/Internal/Schema.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,9 @@ instance ToSchema Float where declareNamedSchema = plain . paramSchemaToSc
624624
instance (Typeable (Fixed a), HasResolution a) => ToSchema (Fixed a) where declareNamedSchema = plain . paramSchemaToSchema
625625

626626
instance ToSchema a => ToSchema (Maybe a) where
627-
declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy a)
627+
declareNamedSchema _ = do
628+
ref <- declareSchemaRef (Proxy @a)
629+
pure $ unnamed $ mempty & oneOf ?~ [Inline $ mempty & type_ ?~ OpenApiNull, ref]
628630

629631
instance (ToSchema a, ToSchema b) => ToSchema (Either a b) where
630632
-- To match Aeson instance

src/Data/OpenApi/Schema/Validation.hs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@ import Data.OpenApi.Internal.Schema.Validation
3434
-- $setup
3535
-- >>> import Control.Lens
3636
-- >>> import Data.Aeson
37+
-- >>> import Data.Aeson.QQ.Simple
3738
-- >>> import Data.Proxy
3839
-- >>> import Data.OpenApi
40+
-- >>> import Data.OpenApi.Declare
3941
-- >>> import GHC.Generics
4042
-- >>> :set -XDeriveGeneric
43+
-- >>> :set -XQuasiQuotes
4144

4245
-- $howto
4346
--
@@ -67,24 +70,18 @@ import Data.OpenApi.Internal.Schema.Validation
6770

6871
-- $maybe
6972
--
70-
-- Because @'Maybe' a@ has the same schema as @a@, validation
71-
-- generally fails for @null@ JSON:
72-
--
73-
-- >>> validateToJSON (Nothing :: Maybe String)
74-
-- ["expected JSON value of type OpenApiString"]
75-
-- >>> validateToJSON ([Just "hello", Nothing] :: [Maybe String])
76-
-- ["expected JSON value of type OpenApiString"]
77-
-- >>> validateToJSON (123, Nothing :: Maybe String)
78-
-- ["expected JSON value of type OpenApiString"]
79-
--
80-
-- However, when @'Maybe' a@ is a type of a record field,
81-
-- validation takes @'required'@ property of the @'Schema'@
82-
-- into account:
73+
-- The behavior is in line with "aeson" behavior for derived instances.
74+
-- When @'Maybe' a@ is a type of a record field,
75+
-- validation accepts both ommited field and null as a field value:
8376
--
8477
-- >>> data Person = Person { name :: String, age :: Maybe Int } deriving Generic
8578
-- >>> instance ToJSON Person
8679
-- >>> instance ToSchema Person
87-
-- >>> validateToJSON (Person "Nick" (Just 24))
80+
-- >>> let (defs, sch) = runDeclare (declareSchema (Proxy :: Proxy Person)) mempty
81+
-- >>> let validate = validateJSON defs sch
82+
-- >>> validate [aesonQQ|{"name" : "Nick", "age" : 18}|]
83+
-- []
84+
-- >>> validate [aesonQQ|{"name" : "Nick", "email" : null}|]
8885
-- []
89-
-- >>> validateToJSON (Person "Nick" Nothing)
86+
-- >>> validate [aesonQQ|{"name" : "Nick"}|]
9087
-- []

0 commit comments

Comments
 (0)