Open fizruk opened 9 years ago
I think we can solve this one by introducing helpers for renaming schemas both at the ToSchema
level and whole-spec. Here's a sketch:
-- | Rename all schema references using a renaming function.
renameSchemas :: Data s => (Text -> Text) -> s -> s
renameSchemas rename = template %~ renameRef
where
renameRef (Ref (Reference name)) = Ref (Reference (rename name))
renameRef (Inline schema) = Inline (renameSchemas rename schema)
-- | Declare a schema reference with all references renamed using a renaming function.
declareRenamedSchemaRef :: ToSchema a =>
(Text -> Text) -> proxy a -> Declare Definitions (Referenced Schema)
declareRenamedSchemaRef rename proxy = do
(defs, schemaRef) <- looks $ runDeclare (declareSchemaRef proxy)
declare $ HashMap.mapKeys rename defs
return $ renameSchemas rename schemaRef
Here's how the example above can be fixed with explicit ToSchema
instance for MyApp.Contact
:
-- MyApp.hs
instance ToSchema Contact where
declareNamedSchema proxy = do
phoneBookContactRef <- declareRenamedSchemaRef rename (Proxy :: Proxy PhoneBook.Contact)
return $ mempty
& schemaType .~ SwaggerObject
& schemaProperties .~
[ ("name", toSchemaRef (Proxy :: Proxy String))
, ("phoneContact", phoneBookContactRef)
, ("facebookContact", toSchemaRef (Proxy :: Proxy String))
, ("googleContact", toSchemaRef (Proxy :: Proxy String)) ]
& schemaRequired .~ ["name", "phoneContact", "facebookContact", "googleContact"]
where
rename "Contact" = "PhoneBookContact"
rename x = x
Alternatively, for this particular example we can use a shorter definition:
instance ToSchema Contact where
declareNamedSchema proxy = do
phoneBookContactRef <- declareRenamedSchemaRef rename (Proxy :: Proxy PhoneBook.Contact)
return (name, schema
& schemaProperties . at "phoneContact" ?~ phoneBookContactRef )
where
(name, schema) = genericToNamedSchema defaultSchemaOptions proxy
rename "Contact" = "PhoneBookContact"
rename x = x
schemaNameModifier
optionI think we should add an option to SchemaOptions
to allow this kind of renaming:
instance ToSchema Contact where
declareNamedSchema = genericDeclareNamedSchema defaultSchemaOptions
{ schemaNameModifier = rename }
where
rename "Contact" = "PhoneBookContact"
rename x = x
@dmjio what do you think about this?
If it looks fine, should we include these helpers and option in v1.0
?
just ran into this problem as well and started thinking about work-arounds. happy to see that's done! :)
ideally, i would like to see a solution that doesn't require the user to think about things (like explicit module paths in the HM keys and in the generated swagger code), and also handles -XPackageImports
correctly (or errors out rather than producing wrong results). but i don't think i'll have time for this any time soon.
anyway :+1: on adding this to a release!
Hypothetical example:
In this example both
MyApp.Contact
andPhoneBook.Contact
have name"Contact"
and therefore schema forMyApp.Contact
becomes recursive which is wrong.Perhaps
datatypeNameModifier
should work with fully qualified names (or it should take module name and datatype name as separate arguments).