aPureBase/KGraphQL

inputType<>() and Type<>() can not be the same

VladislavSumin opened this issue · 5 comments

data class UserDTO(
    val id: Long,
    val name: String,
)

mutation("users") {
    resolver { user: UserDTO ->
        println(user)
        user
    }
}
inputType<UserDTO>()
type<UserDTO>()

when run this configuration i have no error, but query not working, playground show schema infinity loading, inside js console:

buildClientSchema.mjs:256 Uncaught Error: Introspection must provide output type for fields, but received: UserDTO!.

when i use UserDTO only as input or output type so works prerfect

I find bug inside MutableSchemaDefinition:

fun <T : Definition>addType(type: T, target: ArrayList<T>, typeCategory: String){
        <....>
        if(type.checkEqualName(objects, scalars, unions, enums)){ <--- missed inputObjects here
            throw SchemaException("Cannot add $typeCategory type with duplicated name ${type.name}")
        }
        target.add(type)
    }

but i don`t understand why input and output objects can not have same name?

As far as I know, this is a GraphQL limitation. There can't be two types with the same name, and type and input type are two different things.

My workaround for this is to create two classes, anyway in most of the cases the input representation of a type does not have the same properties (eg. the input should have no ID), so this is not a big problem

@VladislavSumin, I don't think you can have the same class for both type and input type.
However, you can use interfaces to the rescue:

interface UserDTO(
    val id: Long
    val name: String
)
data class UserDTOWhereInput: UserDTO(
    override val id: Long,
    override val name: String,
)

mutation("users") {
    resolver { userInput: UserDTOWhereInput ->
        println(userInput)
       val user = users.filter { user -> user.id == userInput.id}
       println("do something with this $user")
        user
    }
}
type<UserDTO>()
inputType<UserDTOWhereInput>()

Hope it helps

I try to use this solution:

type<UserDTO>()
inputType<UserDTOWhereInput>{
    name = "UserDTOInput"
}

that work perfectly.

Then we only need to correct the name verification to take into account inputObjects

if(type.checkEqualName(objects, scalars, unions, enums)){ <--- missed inputObjects here
jeggy commented

Yes, this is a limitation by the GraphQL spec, which can be found here §3.10 Input Objects

The GraphQL Object type (ObjectTypeDefinition) defined above is inappropriate for re‐use here, because Object types can contain fields that define arguments or contain references to interfaces and unions, neither of which is appropriate for use as an input argument. For this reason, input objects have a separate type in the system.

And you will also see this limitation in other implementations/parsers of GraphQL
An example using the IntelliJ GraphQL plugin can be seen here:
image

If you want to use the same Kotlin Class in both a Type and Input Type, then the solution proposed by @VladislavSumin is exactly how you should solve this 👍