I'm trying to build Swagger spec for my Servant project.
Part of my API definition contains internal model objects which have _id
field of type Data.Bson.ObjectId
type API = rest
:<|> "signup" :> ReqBody '[JSON] Credentials :> Post '[JSON] Account
:<|> "signin" :> ReqBody '[JSON] Credentials :> Post '[JSON] Session
So I need to define ToSchema
for Account
and Session
to avoid adding additional layers which will have String
fields instead of ObjectId
, for example.
data Account = Account
{ _id :: ObjectId
, user :: User
, createdAt :: UTCTime
, updatedAt :: UTCTime
} deriving (Generic, Typeable, Show, Read, Eq, Ord)
instance ToBSON Account
instance FromBSON Account
instance ToJSON Account where
toJSON (Account oid user createdAt updatedAt) =
object [ "_id" .= show oid
, "user" .= toJSON user
, "createdAt" .= iso8601Show createdAt
, "updatedAt" .= iso8601Show updatedAt ]
instance FromJSON Account where
parseJSON (Object o) =
Account <$> o .: "_id"
<*> o .: "user"
<*> o .: "createdAt"
<*> o .: "updatedAt"
instance ToSchema Account where
declareNamedSchema proxy = genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped.schema.description ?~ "This is an example of a Account"
& mapped.schema.example ?~ toJSON Model_Account.demo
instance ToSchema User where
declareNamedSchema proxy = genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped.schema.description ?~ "This is an example of a User"
& mapped.schema.example ?~ toJSON Model_User.demo
instance ToSchema Session where
declareNamedSchema proxy = genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped.schema.description ?~ "This is an example of a Session"
& mapped.schema.example ?~ toJSON Model_Session.demo
I also have to implement ToSchema
for ObjectId
and I don't understand how to do that.
instance ToSchema ObjectId where
declareNamedSchema proxy = genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped.schema.description ?~ "This is an example of ObjectId"
& mapped.schema.example ?~ "5e8da2d2393d8b1acd000001"
I get the following error
Data.Swagger.Internal.Schema.genericDeclareNamedSchema
:: SchemaOptions
-> Proxy ObjectId -> Declare (Definitions Schema) NamedSchema
Defined in ‘Data.Swagger.Internal.Schema’
Server.hs:210:30: error:
• Could not deduce: Data.Swagger.Internal.TypeShape.GenericHasSimpleShape
ObjectId
"genericDeclareNamedSchemaUnrestricted"
(Data.Swagger.Internal.TypeShape.GenericShape (Rep ObjectId))
arising from a use of ‘genericDeclareNamedSchema’
• In the first argument of ‘(&)’, namely
‘genericDeclareNamedSchema defaultSchemaOptions proxy’
In the first argument of ‘(&)’, namely
‘genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped . schema . description
?~ "This is an example of ObjectId"’
In the expression:
genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped . schema . description ?~ "This is an example of ObjectId"
& mapped . schema . example ?~ "5e8da2d2393d8b1acd000001"
Server.hs:210:30: error:
• No instance for (Generic ObjectId)
arising from a use of ‘genericDeclareNamedSchema’
• In the first argument of ‘(&)’, namely
‘genericDeclareNamedSchema defaultSchemaOptions proxy’
In the first argument of ‘(&)’, namely
‘genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped . schema . description
?~ "This is an example of ObjectId"’
In the expression:
genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped . schema . description ?~ "This is an example of ObjectId"
& mapped . schema . example ?~ "5e8da2d2393d8b1acd000001"
How can I add ToSchema
implementation for a custom type like ObjectId
which could be easily converted to String
because it implements show
/read
?
• No instance for (Generic ObjectId)
As its name implies, genericDeclareNamedSchema
works only for data types that have an instance of Generic
. ObjectId
does not implement it, so your only option is to declare the schema entirely by hand, see the documentation of ToSchema
for an example.