Pure Kotlin GraphQL implementation

Overview

KGraphQL

Build Status codebeat badge Coverage Status Download Awesome Kotlin Badge

Disclaimer

I am no longer able to maintain this project. Please go to https://github.com/aPureBase/KGraphQL, where KGraphQL is still developed.

KGraphQL is Kotlin implementation of GraphQL. It provides rich DSL to setup GraphQL schema.

Introduction

As example, let's partially reproduce part of Star Wars schema from official GraphQL tutorial. First, we need to define our domain model, by plain kotlin classes:

enum class Episode {
    NEWHOPE, EMPIRE, JEDI
}

interface Character {
    val id : String
    val name : String?
    val friends: List<Character>
    val appearsIn: Set<Episode>
}

data class Human (
        override val id: String,
        override val name: String?,
        override val friends: List<Character>,
        override val appearsIn: Set<Episode>,
        val homePlanet: String,
        val height: Double
) : Character

data class Droid (
        override val id: String,
        override val name: String?,
        override val friends: List<Character>,
        override val appearsIn: Set<Episode>,
        val primaryFunction : String
) : Character

Next, we define our data

val luke = Human("2000", "Luke Skywalker", emptyList(), Episode.values().toSet(), "Tatooine", 1.72)

val r2d2 = Droid("2001", "R2-D2", emptyList(), Episode.values().toSet(), "Astromech")

Then, we can create schema:

//KGraphQL#schema { } is entry point to create KGraphQL schema
val schema = KGraphQL.schema {

        //configure method allows you customize schema behaviour
        configure {
            useDefaultPrettyPrinter = true
        }

        //create query "hero" which returns instance of Character
        query("hero") {
            resolver {episode: Episode -> when(episode){
                Episode.NEWHOPE, Episode.JEDI -> r2d2
                Episode.EMPIRE -> luke
            }}
        }
    
        //create query "heroes" which returns list of luke and r2d2
        query("heroes") {
            resolver{ -> listOf(luke, r2d2)}
        }

        //kotlin classes need to be registered with "type" method 
        //to be included in created schema type system
        //class Character is automatically included, 
        //as it is return type of both created queries  
        type<Droid>()
        type<Human>()
        enum<Episode>()
    }

Now, we can query our schema:

//query for hero from episode JEDI and take id, name for any Character, and primaryFunction for Droid or height for Human
schema.execute("{hero(episode: JEDI){
                    id
                    name 
                    ... on Droid{primaryFunction} 
                    ... on Human{height}
                    }
                }")

Returns:

{
  "data" : {
    "hero" : {
      "id" : "2001",
      "name" : "R2-D2",
      "primaryFunction" : "Astromech"
    }
  }
}

Query for all heroes:

//query for all heroes and take id, name for any Character, and primaryFunction for Droid or height for Human
schema.execute("{heroes {
                    id 
                    name 
                    ... on Droid{primaryFunction} 
                    ... on Human{height}
                    }
                }")

Returns:

{
  "data" : {
    "heroes" : [ {
      "id" : "2000",
      "name" : "Luke Skywalker",
      "height" : 1.72
    }, {
      "id" : "2001",
      "name" : "R2-D2",
      "primaryFunction" : "Astromech"
    } ]
  }
}

As stated by GraphQL specification, client receives only what is requested. No more, no less.

Detailed documentation can be found in wiki. For more examples, see KGraphQL demo application: KGraphQL-NBA2012

Building

To build KGraphQL you only need to have JDK8 installed. invoke

./gradlew build

To perform local build.

Versioning

The versioning is following Semantic Versioning

Links

Specification : http://facebook.github.io/graphql/

License

KGraphQL is Open Source software released under the MIT license

Comments
  • "execute" should take an optional "context" parameter, accessible in the resolver

    One thing that would be very useful (and important) would be if the schema "execute" method could take an additional "context" parameter and then make it accessible in the resolver. That would allow us to add some authorization logic. The context parameter should probably be of generic type (Any)

    On top of that, being able to define ACL properties in the schema and then hook it up to an implementable interface would also be very helpful. Basically, if ACL parameters are applied on schema type, query etc, then just before the query/mutation resolver is called, a registered custom interface works like a proxy and determine if a custom resolver or the targeted resolver is called.

    As an example, Spring Security with it's @PreAuthorize annotation make it easy to apply security on a Sprint Boot Rest API service.

    opened by Paradoxia 13
  • Fragment ...InputValue does not exist

    Fragment ...InputValue does not exist

    I'm trying to create some documentation by using tools available on the internet. Tried both graphdoc and graphql-docs. Unfortunately both of them fail because of the exception Fragment ...InputValue} does not exist.

    Here are the queries that the tools use.

    query IntrospectionQuery {
        __schema {
            queryType {
                name
            }
            mutationType {
                name
            }
            subscriptionType {
                name
            }
            types {
                ...FullType
            }
            directives {
                name
                description
                args {
                    ...InputValue
                }
                onOperation
                onFragment
                onField
            }
        }
    }
    
    fragment FullType on __Type {
        kind
        name
        description
        fields(includeDeprecated: true) {
            name
            description
            args {
                ...InputValue
            }
            type {
                ...TypeRef
            }
            isDeprecated
            deprecationReason
        }
        inputFields {
            ...InputValue
        }
        interfaces {
            ...TypeRef
        }
        enumValues(includeDeprecated: true) {
            name
            description
            isDeprecated
            deprecationReason
        }
        possibleTypes {
            ...TypeRef
        }
    }
    
    fragment InputValue on __InputValue {
        name
        description
        type {
            ...TypeRef
        }
        defaultValue
    }
    
    fragment TypeRef on __Type {
        kind
        name
        ofType {
            kind
            name
            ofType {
                kind
                name
                ofType {
                    kind
                    name
                }
            }
        }
    }
    
    query IntrospectionQuery {
        __schema {
            queryType { name description kind}
            mutationType { name description kind }
            subscriptionType { name description kind }
            types {
                name
                kind
                description
                ...FullType
            }
            directives {
                name
                description
                locations
                args {
                    ...InputValue
                }
            }
        }
    }
    
    
    fragment FullType on __Type {
        fields(includeDeprecated: true) {
            name
            description
            args {
                ...InputValue
            }
            type {
                ...TypeRef
            }
            isDeprecated
            deprecationReason
        }
        inputFields {
            ...InputValue
        }
        interfaces {
            ...TypeRef
        }
        enumValues(includeDeprecated: true) {
            name
            description
            isDeprecated
            deprecationReason
        }
        possibleTypes {
            ...TypeRef
        }
    }
    
    fragment InputValue on __InputValue {
        name
        description
        type { ...TypeRef }
        defaultValue
    }
    
    fragment TypeRef on __Type {
        kind
        name
        description
        ofType {
            kind
            name
            description
            ofType {
                kind
                name
                description
                ofType {
                    kind
                    name
                    description
                    ofType {
                        kind
                        name
                        description
                        ofType {
                            kind
                            name
                            description
                            ofType {
                                kind
                                name
                                description
                                ofType {
                                    kind
                                    name
                                    description
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
    opened by Paradoxia 9
  • Should arg (.withArgs) handle description?

    Should arg (.withArgs) handle description?

    I'm wondering if arg should also handle "description" when doing introspection. Currently i can only set/get "name" and "defaultValue".

    Btw. After experimenting with multiple graphql frameworks (spent a week) i finally came to the conclusion that your library is the best one for Kotlin developers like me. I'm very grateful for your work.

    opened by Paradoxia 8
  • How would I handle query/mutation authentication?

    How would I handle query/mutation authentication?

    Hey!

    First of all, I want to thank you @pgutkowski for making this, it's been a great help in working with GraphQL and Kotlin, taking away a lot of the headaches I was running into before finding this.

    Overall my implementation went fairly smooth. I am able to resolve queries and mutations accurately and even have registration for an app completely done.

    My problem now though, is trying to blend Ktor's JWT and specific queries/mutations together.

    I can protect the graphql route entirely , but that doesn't work well for th registration and login process.

    I know there's a context variable on schema.execute but I'm not certain if this is how I should be passing authentication data down stream.

    opened by pqt 4
  • Issue with 0.3.0-beta / Kotlin 1.3

    Issue with 0.3.0-beta / Kotlin 1.3

    Hi! i'm having this weird issue trying to implement KGrapQL 0.3.0-beta using Kotlin's new release 1.3

    I'm defining this schema:

    val schema = KGraphQL.schema {
    
            configure {
                useDefaultPrettyPrinter = true
            }
    
            query("user") {
                description = "Returns a user by its phone number"
    
                resolver { phoneNumber: String ->
                    userService.getByPhoneNumber(phoneNumber)
                }
            }
    }
    

    And when executing the following code: val result = schema.execute("{user(phoneNumber:\"005491140632747\"){firstName}}")

    I get the following stacktrace:

    java.lang.NoSuchMethodError: kotlinx.coroutines.BuildersKt.launch$default(Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/CoroutineStart;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
    	at com.github.pgutkowski.kgraphql.schema.execution.ParallelRequestExecutor.suspendExecute(ParallelRequestExecutor.kt:53)
    	at com.github.pgutkowski.kgraphql.schema.execution.ParallelRequestExecutor$execute$1.invokeSuspend(ParallelRequestExecutor.kt:89)
    	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
    	at kotlinx.coroutines.DispatchedTask$DefaultImpls.run(Dispatched.kt:235)
    	at kotlinx.coroutines.DispatchedContinuation.run(Dispatched.kt:81)
    	at kotlinx.coroutines.EventLoopBase.processNextEvent(EventLoop.kt:123)
    	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:69)
    	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:45)
    	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:35)
    	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
    	at com.github.pgutkowski.kgraphql.schema.execution.ParallelRequestExecutor.execute(ParallelRequestExecutor.kt:88)
    	at com.github.pgutkowski.kgraphql.schema.DefaultSchema.execute(DefaultSchema.kt:54)
    	at com.github.pgutkowski.kgraphql.schema.Schema$DefaultImpls.execute$default(Schema.kt:8)
    	at com.benkopay.user.UserGraphQLRoutesKt$graphql$1.invokeSuspend(UserGraphQLRoutes.kt:34)
    	at com.benkopay.user.UserGraphQLRoutesKt$graphql$1.invoke(UserGraphQLRoutes.kt)
    	at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
    	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:24)
    	at io.ktor.routing.Routing.executeResult(Routing.kt:110)
    	at io.ktor.routing.Routing.interceptor(Routing.kt:29)
    	at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:75)
    	at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
    	at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
    	at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:60)
    	at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
    	at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
    	at io.ktor.features.StatusPages$intercept$3.invokeSuspend(StatusPages.kt:88)
    	at io.ktor.features.StatusPages$intercept$3.invoke(StatusPages.kt)
    	at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:82)
    	at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:162)
    	at io.ktor.features.StatusPages.intercept(StatusPages.kt:87)
    	at io.ktor.features.StatusPages$Feature$install$1.invokeSuspend(StatusPages.kt:121)
    	at io.ktor.features.StatusPages$Feature$install$1.invoke(StatusPages.kt)
    	at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
    	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:24)
    	at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invokeSuspend(DefaultEnginePipeline.kt:80)
    	at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
    	at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
    	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:24)
    	at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:31)
    	at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
    	at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:54)
    	at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:111)
    	at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:160)
    	at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:54)
    	at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
    	at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:22)
    	at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:16)
    	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    	at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:38)
    	at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:353)
    	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
    	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
    	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:463)
    	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884)
    	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    	at java.lang.Thread.run(Thread.java:748)
    

    gradle.properties:

    logback_version=1.2.1
    ktor_version=1.0.0-beta-3
    kotlin.code.style=official
    kotlin_version=1.3.0
    kgraphql_version=0.3.0-beta
    

    build.gradle:

    buildscript {
        repositories {
            jcenter()
            maven { url 'https://kotlin.bintray.com/kotlin-eap' }
        }
        
        dependencies {
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        }
    }
    
    apply plugin: 'kotlin'
    apply plugin: 'application'
    
    group 'poc-api'
    version '0.0.1-SNAPSHOT'
    mainClassName = "io.ktor.server.netty.EngineMain"
    
    sourceSets {
        main.kotlin.srcDirs = main.java.srcDirs = ['src']
        test.kotlin.srcDirs = test.java.srcDirs = ['test']
        main.resources.srcDirs = ['resources']
        test.resources.srcDirs = ['testresources']
    }
    
    repositories {
        mavenLocal()
        jcenter()
        maven { url 'https://kotlin.bintray.com/ktor' }
        maven { url 'https://kotlin.bintray.com/kotlin-eap' }
    }
    
    dependencies {
        compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
        compile "io.ktor:ktor-server-netty:$ktor_version"
        compile "ch.qos.logback:logback-classic:$logback_version"
        compile "io.ktor:ktor-server-core:$ktor_version"
        compile "io.ktor:ktor-auth:$ktor_version"
        compile "io.ktor:ktor-auth-jwt:$ktor_version"
        compile "io.ktor:ktor-locations:$ktor_version"
        compile "io.ktor:ktor-server-host-common:$ktor_version"
        compile "io.ktor:ktor-gson:$ktor_version"
        compile 'org.koin:koin-ktor:1.0.1'
        compile "com.github.pgutkowski:kgraphql:$kgraphql_version"
    
        compile group: "org.mindrot", name: "jbcrypt", version: "0.4"
    
        compile 'org.jetbrains.exposed:exposed:0.11.1'
        compile "org.postgresql:postgresql:42.2.2"
        compile 'com.zaxxer:HikariCP:2.7.8'
    
        testCompile "io.ktor:ktor-server-tests:$ktor_version"
    }
    

    Of course I tried cleaning, re-building, with new projects, etc.

    I'm kind of new with kotlin, so I do know if the coroutines API had big changes since the 1.3 release and RCs, but it feels like it might have something to do with that.

    Thank you!

    opened by jmarinelli 4
  • Adding Context parameter to resolver causes errors in introspection

    Adding Context parameter to resolver causes errors in introspection

    Adding a Context parameter to a resolver seems to work properly during execution, but introspection comes back with an object that fails to be parsed properly by eg GraphiQL.

    Example resolver:

    mutation("registerAccount") {
      accessRule { ctx ->
        println("rule context: $ctx")
        null
      }
    
      suspendResolver { ctx: Context, email: String ->
        println("resolver context: $ctx")
        println("email: $email")
      }
    }
    

    When executing the function, it does the right thing:

    rule context: com.github.pgutkowski.kgraphql.Context@200146c2
    resolver context: com.github.pgutkowski.kgraphql.Context@200146c2
    email: [email protected]
    

    However, GraphiQL gives the following error when introspecting the schema: Error: Unknown type reference: {"kind":"OBJECT","name":null,"ofType":null}

    In addition, executing with "extra" parameters shows that ctx is incorrectly included in the parameter list: `registerAccount does support arguments [ctx, email]. Found arguments [accountName, email]

    opened by mdnorman 3
  • Make couroutineDispatcher type in configuration generic

    Make couroutineDispatcher type in configuration generic

    Issue: I wanted to override the CoroutineDispatcher in the schema config. Unfortunately that is not possible because the inherited Type is "CommonPool"

    Fix: I changed the type explicity to "CoroutineDispatcher" so the user can override it

    opened by tobias-walle 3
  • GraphiQL:

    GraphiQL: "Error: Mutation fields must be an object with field names as keys or a function which returns such an object."

    I was trying to use this Library in Compination with GraphiQL and got this error on startup:

    Error: Mutation fields must be an object with field names as keys or a function which returns such an object.
        at exports.default (https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.3/graphiql.min.js:1:555767)
        at defineFieldMap (https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.3/graphiql.min.js:1:603654)
        at GraphQLObjectType.getFields (https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.3/graphiql.min.js:1:612074)
        at typeMapReducer (https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.3/graphiql.min.js:1:646345)
        at Array.reduce (<anonymous>)
        at new GraphQLSchema (https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.3/graphiql.min.js:1:650422)
        at exports.buildClientSchema (https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.3/graphiql.min.js:1:679897)
        at https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.3/graphiql.min.js:1:46309
        at <anonymous>
    

    I got the following setup:

    data class HelloWorld(val id: Int, val name: String, val optional: Boolean? = null)
    
    @Configuration
    class GraphQLConfiguration {
      @Bean()
      fun schema() = KGraphQL.schema {
        query("hero") {
          resolver { -> HelloWorld(1, "hello") }
        }
    
        type<HelloWorld>()
      }
    }
    

    The query GraphiQL executes is the following:

    {"query":"\n  query IntrospectionQuery {\n    __schema {\n      queryType { name }\n      mutationType { name }\n      subscriptionType { name }\n      types {\n        ...FullType\n      }\n      directives {\n        name\n        description\n        locations\n        args {\n          ...InputValue\n        }\n      }\n    }\n  }\n\n  fragment FullType on __Type {\n    kind\n    name\n    description\n    fields(includeDeprecated: true) {\n      name\n      description\n      args {\n        ...InputValue\n      }\n      type {\n        ...TypeRef\n      }\n      isDeprecated\n      deprecationReason\n    }\n    inputFields {\n      ...InputValue\n    }\n    interfaces {\n      ...TypeRef\n    }\n    enumValues(includeDeprecated: true) {\n      name\n      description\n      isDeprecated\n      deprecationReason\n    }\n    possibleTypes {\n      ...TypeRef\n    }\n  }\n\n  fragment InputValue on __InputValue {\n    name\n    description\n    type { ...TypeRef }\n    defaultValue\n  }\n\n  fragment TypeRef on __Type {\n    kind\n    name\n    ofType {\n      kind\n      name\n      ofType {\n        kind\n        name\n        ofType {\n          kind\n          name\n          ofType {\n            kind\n            name\n            ofType {\n              kind\n              name\n              ofType {\n                kind\n                name\n                ofType {\n                  kind\n                  name\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n"}
    

    which returns the this result (which causes the error):

    {"data":{"__schema":{"queryType":{"name":"Query"},"mutationType":{"name":"Mutation"},"subscriptionType":null,"types":[{"kind":"OBJECT","name":"HelloWorld","description":"","fields":[{"name":"id","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"optional","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Schema","description":"","fields":[{"name":"directives","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Directive","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"mutationType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"queryType","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"subscriptionType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"types","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Directive","description":"","fields":[{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"locations","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__DirectiveLocation","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"onField","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":true,"deprecationReason":"Use `locations`."},{"name":"onFragment","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":true,"deprecationReason":"Use `locations`."},{"name":"onOperation","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":true,"deprecationReason":"Use `locations`."}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__InputValue","description":"","fields":[{"name":"defaultValue","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Type","description":"","fields":[{"name":"description","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"enumValues","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__EnumValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"fields","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Field","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"inputFields","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"interfaces","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"kind","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__TypeKind","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"ofType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"possibleTypes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__EnumValue","description":"","fields":[{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Field","description":"","fields":[{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__TypeKind","description":"","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"SCALAR","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"LIST","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"NON_NULL","description":null,"isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"ENUM","name":"__DirectiveLocation","description":"","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"QUERY","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"MUTATION","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"SUBSCRIPTION","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"FIELD","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_DEFINITION","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_SPREAD","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"INLINE_FRAGMENT","description":null,"isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"SCALAR","name":"String","description":"The String scalar type represents textual data, represented as UTF‐8 character sequences","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Boolean","description":"The Boolean scalar type represents true or false","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Float","description":"The Float scalar type represents signed double‐precision fractional values as specified by IEEE 754","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Int","description":"The Int scalar type represents a signed 32‐bit numeric non‐fractional value","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Long","description":"The Long scalar type represents a signed 64‐bit numeric non‐fractional value","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Mutation","description":"Mutation object","fields":[],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Query","description":"Query object","fields":[{"name":"hero","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"HelloWorld","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null}],"directives":[{"name":"skip","description":null,"locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":null,"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"include","description":null,"locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":null,"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]}]}}}
    

    My guess is that GraphiQL requires the mutation fields.

    After adding some mutation fields the error disappeared:

    data class HelloWorld(val id: Int, val name: String, val optional: Boolean? = null)
    
    @Configuration
    class GraphQLConfiguration {
      @Bean()
      fun schema() = KGraphQL.schema {
        query("hero") {
          resolver { -> HelloWorld(1, "hello") }
        }
    
        mutation("test") {
          resolver { -> HelloWorld(2, "test", false) }
        }
    
        type<HelloWorld>()
      }
    }
    

    The new query output is the following:

    {"data":{"__schema":{"queryType":{"name":"Query"},"mutationType":{"name":"Mutation"},"subscriptionType":null,"types":[{"kind":"OBJECT","name":"HelloWorld","description":"","fields":[{"name":"id","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"optional","description":null,"args":[],"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Schema","description":"","fields":[{"name":"directives","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Directive","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"mutationType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"queryType","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"subscriptionType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"types","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Directive","description":"","fields":[{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"locations","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__DirectiveLocation","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"onField","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":true,"deprecationReason":"Use `locations`."},{"name":"onFragment","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":true,"deprecationReason":"Use `locations`."},{"name":"onOperation","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":true,"deprecationReason":"Use `locations`."}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__InputValue","description":"","fields":[{"name":"defaultValue","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Type","description":"","fields":[{"name":"description","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"enumValues","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__EnumValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"fields","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":null}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Field","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"inputFields","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"interfaces","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"kind","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__TypeKind","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"ofType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"possibleTypes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__EnumValue","description":"","fields":[{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Field","description":"","fields":[{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__TypeKind","description":"","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"SCALAR","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"LIST","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"NON_NULL","description":null,"isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"ENUM","name":"__DirectiveLocation","description":"","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"QUERY","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"MUTATION","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"SUBSCRIPTION","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"FIELD","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_DEFINITION","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_SPREAD","description":null,"isDeprecated":false,"deprecationReason":null},{"name":"INLINE_FRAGMENT","description":null,"isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"SCALAR","name":"String","description":"The String scalar type represents textual data, represented as UTF‐8 character sequences","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Boolean","description":"The Boolean scalar type represents true or false","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Float","description":"The Float scalar type represents signed double‐precision fractional values as specified by IEEE 754","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Int","description":"The Int scalar type represents a signed 32‐bit numeric non‐fractional value","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Long","description":"The Long scalar type represents a signed 64‐bit numeric non‐fractional value","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Mutation","description":"Mutation object","fields":[{"name":"test","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"HelloWorld","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Query","description":"Query object","fields":[{"name":"hero","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"HelloWorld","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null}],"directives":[{"name":"skip","description":null,"locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":null,"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"include","description":null,"locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":null,"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]}]}}}
    

    I don't know if this is an issue with GraphiQL or this library. I found a similar issue on "graphql-ruby", which got fixed. Issue Fix.

    If I find the time I might try to fix it by myself.

    opened by tobias-walle 3
  • Merging schemas would be helpful

    Merging schemas would be helpful

    I'm currently working on wrapping multiple rest- and microservices into a single graphql schema. The only problem I have is that my single schema becomes very bloated and large. It would be very helpful if it was possible to merge multiple schemas into one single schema.

    Again thank you very much for your awesome framework :)

    opened by Paradoxia 3
  • store allType in a list rather than a map index by kotlin class.

    store allType in a list rather than a map index by kotlin class.

    Allows reusing the same kotlin type (with a different name attribute) in a gql type and a gql inputType.

    Avoids many useless kotlin type duplication to circumvent GraphQL constraint that output types cannot be input types (even when it's totally legit).

    Example use :

    val schema = KGraphQL.schema {
        inputType<MyKotlinType>() {
            name="TypeAsInput"
        }
        type<MyKotlinType>() {
            name="TypeAsObject"
        }
    }
    
    opened by adminfairjungle 2
  • Is this the right way with using resolvers on a type?

    Is this the right way with using resolvers on a type?

    I have the following type which contains:

     type<VehicleResponse> {
                description = "Gadget returned from original GadgetProxy"
    
                property(VehicleResponse::gadget) {
                    description = "Integer value representing type of vehicle"
                }
    
                property<InventoryParts?>("inventory") {
                    resolver { response, fromDate: LocalDate ->
                        getInventoryParts(response.gadget.stockNumber, fromDate)
                    }
                }
            }
    
    

    I also have :

     query("getInventory") {
                description = "Returns the parts from the inventory."
                resolver { stockNumber: String, fromDate: LocalDate ->
                    getInventoryParts(stockNumber, fromDate)
                }.withArgs {
                    arg<String> { name = "fromDate"; description = "Date to check inventory stock" }
                }
            }
    

    As you can see there is a bit of duplication (getInventoryParts). So my question is am I using the resolver correctly when defining the schema or can I some how from VehicleResponse go to query("getInventory") rather than creating a resolver in my VehicleResponse type?

    opened by shamresh 2
  • release 0.3.1 build?

    release 0.3.1 build?

    Hi there,

    I'd love to use the context functionality mentioned in #42, #47. But it seems as if release 0.3.1 that contains the relevant changes (omit introspection of the Context type) has never been build. @pgutkowski can you help here?

    Cheers, Martin

    opened by martinheld 2
  • When overwriting a property, the GraphQL repeats the original property unless ignored

    When overwriting a property, the GraphQL repeats the original property unless ignored

    I have a class that has an id field, but I don't want to use it directly. Instead, I want to replace its implementation with a derivative function and type with another type. I want to do this by just adding a replacement field of the same name. But this requires to ignore the original property, which is strange.

    My expectation is that if creating a new field with the same name that it would automatically ignore the original property.

    opened by mdnorman 0
  • Allow a kotlin type to be used as graphql type and inputType

    Allow a kotlin type to be used as graphql type and inputType

    Allows reusing the same kotlin type (with a different name attribute) in a gql type and a gql inputType.

    Avoids many useless kotlin type duplication to circumvent GraphQL constraint that output types cannot be input types (even when it's totally legit).

    Example use :

    val schema = KGraphQL.schema { inputType() { name="TypeAsInput" } type() { name="TypeAsObject" } }

    opened by Bertrand 2
  • enable building graphql schema using KFunction method references

    enable building graphql schema using KFunction method references

    Many times a project already has Services with methods. These methods can have many arguments and it is tedious to expose them with the lambda style that is currently supported.

    These changes allow using KFunction method references which include all argument information and reduce boilerplate.

    For example:

    val mlService = MovieLensService(MovieRepository, GenresRepository, OccupationRepository, RatingRepository, UserRepository)
    
    val schema = KGraphQL.schema{
        query("allUsers"){
            resolver{ -> mlService.getAllUsers() }
        }
    
        query("getUser"){
            resolver{ id: Int -> mlService.getUser(id) }
        }
    
        mutation("createUser"){
            resolver{ age: Int, gender: String, occupationId: Long, zipCode: String ->  mlService.createUser(age, gender, occupationId, zipCode) }
        }
    }
    

    becomes:

    val mlService = MovieLensService(MovieRepository, GenresRepository, OccupationRepository, RatingRepository, UserRepository)
    
    val schema = KGraphQL.schema{
        query("allUsers"){
            mlService::getAllUsers.toResolver()
        }
    
        query("getUser"){
            mlService::getUser.toResolver()
        }
    
        mutation("createUser"){
            mlService::createUser.toResolver()
        }
    }
    
    opened by pabl0rg 1
  • Caused by: java.lang.NoClassDefFoundError: kotlinx/coroutines/experimental/CommonPool

    Caused by: java.lang.NoClassDefFoundError: kotlinx/coroutines/experimental/CommonPool

    when creating val appSchema = AppSchema(userServiceImpl) get error, somth wrong with coroutines syntax. Error appear when we try to create schema val schema = KGraphQL.schema {

    > 
    > Exception in thread "main" java.lang.reflect.InvocationTargetException
    > 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    > 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    > 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    > 	at java.lang.reflect.Method.invoke(Method.java:498)
    > 	at kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97)
    > 	at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Static.call(CallerImpl.kt:106)
    > 	at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod$kotlin_reflect_api(KCallableImpl.kt:166)
    > 	at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:110)
    > 	at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.callFunctionWithInjection(ApplicationEngineEnvironmentReloading.kt:349)
    > 	at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.executeModuleFunction(ApplicationEngineEnvironmentReloading.kt:299)
    > 	at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.instantiateAndConfigureApplication(ApplicationEngineEnvironmentReloading.kt:275)
    > 	at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createApplication(ApplicationEngineEnvironmentReloading.kt:127)
    > 	at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.start(ApplicationEngineEnvironmentReloading.kt:247)
    > 	at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:106)
    > 	at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:18)
    > 	at io.ktor.server.engine.ApplicationEngine$DefaultImpls.start$default(ApplicationEngine.kt:52)
    > 	at io.ktor.server.netty.EngineMain.main(EngineMain.kt:17)
    > 	at com.fashion.ApplicationKt.main(Application.kt:34)
    > Caused by: java.lang.NoClassDefFoundError: kotlinx/coroutines/experimental/CommonPool
    > 	at com.github.pgutkowski.kgraphql.schema.dsl.SchemaConfigurationDSL.<init>(SchemaConfigurationDSL.kt:16)
    > 	at com.github.pgutkowski.kgraphql.schema.dsl.SchemaBuilder.<init>(SchemaBuilder.kt:18)
    > 	at com.github.pgutkowski.kgraphql.KGraphQL$Companion.schema(KGraphQL.kt:8)
    > 	at db.graphql.AppSchema.<init>(AppSchema.kt:8)
    > 	at web.UserRoutesKt.users(UserRoutes.kt:18)
    > 	at com.fashion.ApplicationKt$module$5.invoke(Application.kt:94)
    > 	at com.fashion.ApplicationKt$module$5.invoke(Application.kt)
    > 	at io.ktor.routing.Routing$Feature.install(Routing.kt:92)
    > 	at io.ktor.routing.Routing$Feature.install(Routing.kt:78)
    > 	at io.ktor.application.ApplicationFeatureKt.install(ApplicationFeature.kt:59)
    > 	at io.ktor.routing.RoutingKt.routing(Routing.kt:121)
    > 	at com.fashion.ApplicationKt.module(Application.kt:87)
    > 	at com.fashion.ApplicationKt.module$default(Application.kt:38)
    > 	... 18 more
    > Caused by: java.lang.ClassNotFoundException: kotlinx.coroutines.experimental.CommonPool
    > 	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    > 	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    > 	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    > 	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    > 	... 31 more
    
    opened by artem-bakuta 1
  • Implement a DataLoaderDSL for batching

    Implement a DataLoaderDSL for batching

    Implement DataLoader style.

    I've been thinking about a structure like this:

    ...
    data class Tree(val id: String, val parentId: String?)
    ...
    type<Tree> {
        // String - defines the key that will be sent from the [prepare] into [loader]
        // List<Tree> - defines the return type that the [loader] is required to return.
        // the loader is then required to return it in a map format like Map<String, List<Tree>>
        dataProperty<String, List<Tree>>("children") {
            // Step 2: This will only be called once.
            loader { keys: List<String> ->
                keys.map{ id -> id to listOf(Tree("SomeId", id)) }.toMap()
            }
        
            // Step 1: This will be called for each node in the list, or only once if it's not a list
            prepare { parent: Tree -> parent.id }
        }
    }
    

    Anyone is welcome with some input on how this could be achieved.

    opened by jeggy 0
Owner
Paweł Gutkowski
Paweł Gutkowski
GraphQL Jetpack - A collection of packages for easily writing Java GraphQL server implementations

GraphQL Jetpack A collection of packages for easily writing Java GraphQL server

Ryan Yang 18 Dec 2, 2022
Victor Hugo 1 Feb 2, 2022
🗼 yukata (浴衣) is a modernized and fast GraphQL implementation made in Kotlin

?? yukata 浴衣 - Modernized and fast implementation of GraphQL made in Kotlin yukata is never meant to be captialised, so it'll just be yukata if you me

Noel 5 Nov 4, 2022
A sample skeleton backend app built using Spring Boot kotlin, Expedia Kotlin Graphql, Reactive Web that can be deployed to Google App Engine Flexible environmennt

spring-kotlin-gql-gae This is a sample skeleton of a backend app that was built using: Spring Boot(Kotlin) Reactive Web Sprinng Data R2DBC with MYSQL

Dario Mungoi 7 Sep 17, 2022
Kotlin backend based on the Clean Architecture principles. Ktor, JWT, Exposed, Flyway, KGraphQL/GraphQL generated endpoints, Gradle.

Kotlin Clean Architecture Backend Kotlin backend based on the Clean Architecture principles. The application is separated into three modules: Domain,

null 255 Jan 3, 2023
An application that simulate the Swedish Transport Agency, implemented with Spring Boot, Kotlin and GraphQL

graphql-kotlin-spring-server An application that simulate the Swedish Transport Agency, implemented with Spring Boot, Kotlin and GraphQL Running the s

null 0 Oct 31, 2021
A simple reference example Kotlin GraphQL service

A simple reference example Kotlin GraphQL service, written for colleagues coming over from Python & FastAPI/Flask + Ariadne/Graphene.

Dan Pozmanter 5 Mar 20, 2022
GraphQL for Java with Spring Boot made easy.

GraphQL for Java with Spring Boot made easy.

Netflix, Inc. 2.5k Jan 9, 2023
This repository demonstrates Spring GraphQL + RSocket + WebFlux + R2DBC + H2

Reactive GraphQL with Spring This repository demonstrates Spring GraphQL + RSocket + WebFlux + R2DBC + H2 O__ +-----------+

Maksim Kostromin 1 Nov 27, 2021
PeopleInSpace GraphQL Server

PeopleInSpace GraphQL Server GraphQL backend allowing querying list of people in

John O'Reilly 5 Oct 4, 2022
Template to accelerate the creation of new apps using Spring Boot 3, MongoDB & GraphQL.

Template to accelerate the creation of new apps using Spring Boot 3, MongoDB & GraphQL.

André Ramon 1 Feb 13, 2022
Koltin Multplatform Project that interacts with a GraphQL server to display golf scores, player and weather information.

GolfScoresKMM Koltin Multplatform Project that interacts with a GraphQL server to display golf scores, player and weather information. The app is setu

Mohit 15 Oct 21, 2022
Mock up social media android application created to interact with a backend Java server using GraphQL.

The Community Board Project Authorship: author: dnglokpor date: may 2022 Project Summary: The Community Board Project consists of a Java Spring Boot b

Delwys Glokpor 1 May 17, 2022
Saga pattern implementation in Kotlin build in top of Kotlin's Coroutines.

Module Saga Website can be found here Add in build.gradle.kts repositories { mavenCentral() } dependencies { implementation("io.github.nomisr

Simon Vergauwen 50 Dec 30, 2022
📒 NotyKT is a complete 💎Kotlin-stack (Backend + Android) 📱 application built to demonstrate the use of Modern development tools with best practices implementation🦸.

NotyKT ??️ NotyKT is the complete Kotlin-stack note taking ??️ application ?? built to demonstrate a use of Kotlin programming language in server-side

Shreyas Patil 1.4k Dec 26, 2022
A Zero-Dependency Kotlin Faker implementation built to leave you fully satisfied

Satisfaketion A Zero-Dependency Kotlin Faker implementation built to leave you fully satisfied ?? ... With your fake data How to Install ?? Satisfaket

Ryan Brink 7 Oct 3, 2022
📌This repo contains the kotlin implementation of TensorflowLite Example Android Apps🚀

TensorflowLite Examples Kotlin This repo contains the kotlin implementation of TensorflowLite Example Apps here, which are mostly implemented in java

Sunit Roy 28 Dec 13, 2022
An implementation of MediatR on JVM for Spring using Kotlin coroutines

Kpring MediatR In this project, an attempt has been made to implement the mediator pattern on the JVM with simplicity using Kotlin with native corouti

Mahdi Bohloul 4 Aug 6, 2022
Kotlin implementation of WalletConnect v2 protocol for Android applications

WalletConnect V2 - Kotlin Kotlin implementation of WalletConnect v2 protocol for

WalletConnect 92 Jan 6, 2023