sangria-graphql / sangria

Scala GraphQL implementation
https://sangria-graphql.github.io
Apache License 2.0
1.96k stars 226 forks source link

DeriveInputObjectType for traits? #285

Closed kevinmu closed 6 years ago

kevinmu commented 7 years ago

http://sangria-graphql.org/learn/ says that deriveInputObjectType supports only case classes. Meanwhile, deriveObjectType and deriveContextObjectType support arbitrary case classes as well as normal classes/traits. I'm wondering why there is the additional limitation on deriveInputObjectType? For instance, I have the following scenario I'm trying to implement:

case class TeamInput(name: String, members: List[PersonInput])

trait PersonInput {
  def name: String
}
case class BuilderInput(name: String, building: BuildingEnum) extends PersonInput
case class WorkerInput(name: String, factory: FactoryEnum) extends PersonInput

However, I can't create a valid InputObjectType for TeamInput because I cannot create an InputObjectType on PersonInput. The error I get when trying to use deriveInputObjectType is:

[error] .../Inputs.scala:63: Unknown member 'name'. Known members are: 
[error]       DocumentInputField("name", "name of the person.")

Not only am I unable to use deriveInputObjectType, but even manually using the Sangria DSL to create an implicit value of type InputObjectType[PersonInput] gives me the following error at compile time:

Can't find suitable GraphQL input type for List[PersonInput].
If you have defined it already, please consider making it implicit and ensure that it's available in the scope. 

Note that if I convert PersonInput to a case class (and get rid of BuilderInput and WorkerInput), then the compilation succeeds. Would greatly appreciate any advice on this, thanks!

OlegIlyenko commented 7 years ago

By default, input object derivation only supports the case classes, as you mentioned. But the mechanism behind it is quite extensible and relies heavily on the FromInput type-class. The reason that it only supports the case classes is directly related to the support of object serialization by different JSON libraries since the deserialization is delegated to these libraries.

That said, the type-class mechanism itself is quite flexible. If you have some special deserialization logic, you can just define an implicit instance of FromInput[PersonInput].

I also would like to point out that within GraphQL type system input objects do not support polymorphism of any kind. So it would not be possible to express the same relation between PersonInput/BuilderInput/WorkerInput types in GraphQL type system.

kevinmu commented 7 years ago

Ah okay, I hadn't read https://github.com/graphql/graphql-js/issues/207 or https://github.com/facebook/graphql/issues/114, so I didn't realize that GraphQL didn't support polymorphism! I guess I'll just have to find a work-around for what I want to accomplish.

Thanks so much for the helpful reply!

OlegIlyenko commented 6 years ago

Closing since original question is answered. Please feel free to reopen if you would have further questions.