-
Notifications
You must be signed in to change notification settings - Fork 325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
schema-profunctor: Add ToSchema instance for lists #1497
Conversation
@@ -563,6 +563,8 @@ instance ToSchema String where schema = genericToSchema | |||
|
|||
instance ToSchema Bool where schema = genericToSchema | |||
|
|||
instance (S.ToSchema a, A.ToJSON a, A.FromJSON a)=> ToSchema [a] where schema = genericToSchema |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer this:
instance (S.ToSchema a, A.ToJSON a, A.FromJSON a)=> ToSchema [a] where schema = genericToSchema | |
instance ToSchema a => ToSchema [a] where schema = array schema |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, is there a difference. This does look better, asking for my education.
I also pushed another instance for NonEmpty a
I am guessing array
wouldn't produce a nice ToSchema instance for that, so we should use genericToSchema
in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I can see the difference, if we the one I made, it would ignore a ToSchema
explicitly defined for a
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think genericToSchema
should only be used for bootstrapping primitive types, but not for instances that recurse over previously defined schemas. There isn't a huge difference in this case, but maybe in the future we might get rid of the S.ToSchema
instances altogether (and simply convert the top-level SchemaP
's to a named swagger schema when we generate the swagger), in which case this wouldn't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, array schema
doesn't work as it doesn't produce a named schema, so either I need a TypeRep
, which would be annoying or I need to set it to something like an empty string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you're right, on both counts.
I think it's better not to have this instance. One can just use array
when you need an array, since lists are indeed most commonly unnamed.
Similarly, I would add a nonEmptyArray
combinator instead of the NonEmpty
instance.
e7f8495
to
e984d23
Compare
@@ -563,6 +564,10 @@ instance ToSchema String where schema = genericToSchema | |||
|
|||
instance ToSchema Bool where schema = genericToSchema | |||
|
|||
instance (S.ToSchema a, A.ToJSON a, A.FromJSON a) => ToSchema [a] where schema = genericToSchema | |||
|
|||
instance (S.ToSchema a, A.ToJSON a, A.FromJSON a) => ToSchema (NonEmpty a) where schema = genericToSchema |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also like to define this in terms of ToSchema a
rather than S.ToSchema a
. It should be possible to use array
, and then withParser
to convert it into a non-empty list.
…oSchema Declaring instances using S.ToSchema and A.{To,From}JSON is a little problematic as it wouldn't use an explicitly defined P.ToSchema, so instead of using instances for P.ToSchema, users will be expected to use the combinators as required.
nonEmptyArray :: | ||
forall ndoc doc a.(HasArray ndoc doc, HasName ndoc, S.HasMinItems doc (Maybe Integer)) => | ||
ValueSchema ndoc a -> | ||
ValueSchema doc (NonEmpty a) | ||
nonEmptyArray sch = SchemaP (SchemaDoc s) (SchemaIn r) (SchemaOut w) | ||
where | ||
name = maybe "non-empty array" ("non-empty array of " <>) (getName (schemaDoc sch)) | ||
r = A.withArray (T.unpack name) $ \arr -> case V.toList arr of | ||
[] -> A.parseFail "Unexpected empty array found while parsing a NonEmpty" | ||
(x : xs) -> mapM (schemaIn sch) (x :| xs) | ||
s = mkArray (schemaDoc sch) & S.minItems ?~ 1 | ||
w xs = A.Array . V.fromList <$> mapM (schemaOut sch) (NonEmpty.toList xs) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be possible to use array
instead of reimplementing its functionality. Something like:
nonEmptyArray sch = NonEmpty.toList .= array sch `withParser` check
where
check = maybe (fail "Unexpected empty array found while parsing a NonEmpty") pure
. NonEmpty.nonEmpty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't make the swagger work nicely, thought it was ok to have a small amount of duplication. Maybe we can look at it together after lunch to get it to work?
@@ -316,6 +318,19 @@ array sch = SchemaP (SchemaDoc s) (SchemaIn r) (SchemaOut w) | |||
s = mkArray (schemaDoc sch) | |||
w x = A.Array . V.fromList <$> mapM (schemaOut sch) x | |||
|
|||
nonEmptyArray :: | |||
forall ndoc doc a.(HasArray ndoc doc, HasName ndoc, S.HasMinItems doc (Maybe Integer)) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not super important, but the combinators do not depend on Swagger so far. Would it possible to have a locally defined type class to set the minimum, instead of using S.HasMinItems?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I first added it to HasArray
, but it didn't look very nice as the lens doesn't depend on the ndoc
variable and it has to be type applied. I will defined a similar class, that should also work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did this now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apart from the possible simplification of the minItems
lens, looks good to me.
instance HasMinItems SwaggerDoc (Maybe Integer) where | ||
minItems = | ||
lens | ||
(\(WithDeclare _ s) -> s & view S.minItems) | ||
(\(WithDeclare d s) mInt -> WithDeclare d $ s & S.minItems .~ mInt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this one could simply be a lens composition: minItems = declared . S.minItems
or similar.
No description provided.