Quarkus: GraphQL schema generation does not handle sealed classes

Created on 21 Oct 2020  路  23Comments  路  Source: quarkusio/quarkus

Describe the bug
Sealed classes are ignored when generating the schema, causing issues with inner classes with same name.

Expected behavior

sealed class SealedClassA {
       data class Response(val propertyA: String)
}
sealed class SealedClassB {
       data class Response(val propertyB: String)
}

Generated schema:

type Response extends SealedClassA {
       propertyA: String
}
type ClassOne extends SealedClassB {
       propertyB: String
}

Actual behavior
Generated schema:

type Response {
       propertyA: String
}
aregraphql aresmallrye kinquestion

All 23 comments

/cc @phillip-kruger, @jmartisk

I don't think that the class being sealed or not is really relevant here. The problem here is that you have two GraphQL types that map to the same name, because we use the unqualified class name by default. Perhaps we should improve the code to detect that and throw an error... Anyway would it help if you differentiated your classes with @Name("CUSTOM-NAME") to mitigate the name clash?

The error handling would be a nice thing to add since it's very hard to understand the root cause.
This is the error I currently get: _Validation error of type FieldUndefined_.
I've tried to use the @Name tag, but the name is not being overridden and the class name is the one used in the schema.

Do you have a reproducer ?

@phillip-kruger I don't, sorry

If you can create one, that would help a lot

I'll try and create something (I already did for a bit of experimenting), at least we'll make sure we're all on the same page

btw I think you might be the first person ever trying the GraphQL extension with Kotlin... This thing will definitely need some more care.

https://github.com/jmartisk/graphql-kotlin-experiment
This is what I understood from the description that you're trying to do. I added the @Name annotations in SealedA.kt and SealedB.kt to demonstrate that after differentiating the two classes, it works properly:

@Name("RESPONSE_A")
class Response : SealedClassA { .... }

@Name("RESPONSE_B")
class Response : SealedClassB { .... }

the schema now is:

type RESPONSE_A {
  propertyA: String
  propertyInResponseA: String
}

type RESPONSE_B {
  propertyB: String
  propertyInResponseB: String
}

Without the annotations, both response classes are wrongly mapped to the same GraphQL type, and thus one of them stops working properly

Sorry, I cannot try with your demo at the moment, but will do that later.
The main difference I see is in the model, I have only one file like this, let's say SealedClasses.kt:

sealed class SealedClassA {
   @Name("RESPONSE_A")
   data class Response {
      lateinit var propertyInResponseA: String
   }
}

sealed class SealedClassB {
   @Name("RESPONSE_B")
   data class Response {
      lateinit var propertyInResponseB: String
   }
}

I managed to make it work in your demonstration. Thanks!

Great to hear it's working. I reported https://github.com/smallrye/smallrye-graphql/issues/482 to fix the issue where we don't throw an error if multiple classes map to the same GraphQL type

Anyway, not being able to use the @Name tag on our project, due to not wanting to add new dependencies, it would be nice to have a way of fixing this other than having data classes with different names.

@aritabrito Not sure what you mean, if you're using GraphQL then you must have the org.eclipse.microprofile.graphql package available anyway, and @Name is in that package?!

It's in two different services, one just for the dtos where I have the sealed classes. That's the one without the package

You can also use jsonbproperty to name it

You can also use jsonbproperty to name it

That AFAIK only affects the output JSON, not the schema, so the schema would still be invalid?

Anyway, I think another problem here is that if a model class is nested, we only use the inner class' name for the type, perhaps we should translate it to OuterClass_InnerClass?? I think that would solve @aritabrito 's problem, the Response classes in the description are nested.
It wouldn't solve the problem when the outer AND inner classes are named the same BUT are in a different package, but that's not the case here AFAICS

Yep, that would solve the issue! 馃憤

I added a config option that allow the naming strategy a while back, you can even use the full package name, or inner classes can be pretended with their parent class

Try setting quarkus.smallrye-graphql.auto-name-strategy=MergeInnerClass

Or Full to get the whole package

Oh I didn't know that, ok. Note that this is only available since Quarkus 1.9.0

Wow! It worked! Thanks a lot 馃挴

Was this page helpful?
0 / 5 - 0 ratings