Git Product home page Git Product logo

kgraphql's People

Contributors

bertrand avatar jeggy avatar kimar avatar mdnorman avatar nikkyai avatar pgutkowski avatar swiftrs avatar tobias-walle avatar vemilyus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kgraphql's Issues

Usage with Dataloaders?

Is there any way I can make this work with dataloaders i.e. the one that comes default with graphql java or node dataloader js libs?

Support object literal arguments

Are there plans to support these? Your library is my favorite GraphQL library for Java/Kotlin, but not being able to send objects to my mutations makes it a deal-breaker for many of my projects.

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 :)

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!

dsl?

What is dsl?
It provides rich DSL to setup GraphQL schema ...

Resolvers on user types?

Interesting approach!

I can't find in the examples: does KGraphQL support resolvers on user types? (not just query and mutation)

Fragments not resolving correctly on same data node

Having an issue where fragments that operate on the same data node are not being merged, rather only the last fragment is being resolved.

Setup

data class Contact(val name: Name = Name())
data class Name(val firstName: String = "Bob", val lastName: String = "Jones")
 KGraphQL.schema {
        query("contact") {
            resolver { -> Contact() }
        }

        type<Contact> { }
}

A simple query resolves correctly

{
  contact {
    name {
      firstName
      lastName
    }
  }
}

Result

{
  "data": {
    "contact": {
      "name": {
        "firstName": "Bob",
        "lastName": "Jones"
      }
    }
  }
}

But when multiple fragments are used that operate on name only the last is resolved

fragment firstName on Contact {
  name {
    firstName
  }
}

fragment lastName on Contact {
  name {
    lastName
  }
}

{
  contact {
     ...firstName
     ...lastName
  }
}

Result

{
  "data": {
    "contact": {
      "name": {
        "lastName": "Jones"
      }
    }
  }
}

The fragments work as expected when used independently, and if they operate on different nodes of data they both resolve.

Expected
Both fragment should be resolved and firstName and lastName returned. That's my understanding of the spec, and I ran a similar experiment against express-graphql and it merges correctly. This leads me to believe it's a bug within KGraphQL.

Scalar types within variables not working

It's failing when trying to use scalar types within variables. See example below.

// This test should be in `ScalarsSpecificationTest`
@Test
fun `Scalars within input variables`(){
    val schema = KGraphQL.schema {
        floatScalar<Dob> {
            deserialize = ::Dob
            serialize = { (double) -> double }
        }

        query("double"){
            resolver { double : Dob -> double }
        }
    }

    val value = 232.33
    val response = deserialize(schema.execute(
        request = "query customQuery(\$var: Dob!){double(double: \$var)}",
        variables = "{\"var\": $value}"
    ))
    assertThat(response.extract<Double>("data/double"), equalTo(value))
}

Gives:

com.github.pgutkowski.kgraphql.ExecutionException: Failed to coerce 232.33 as com.github.pgutkowski.kgraphql.specification.typesystem.ScalarsSpecificationTest.Dob

KProperty.ignore() should cascade to subclasses

Let's say I have two classes, one being a subclass of the other. The parent class has a property that I want to be ignored in GraphQL. I currently have to use KProperty.ignore() on both types.

open class A (val title: String)
class B(title: String) : A(title)

val schema = schema {
    type<A> {
        A::title.ignore() // This does not apply to B
    }
    
    type<B> {
        B::title.ignore() // I have to explicitly ignore it here too
    }
}

I feel like using ignore() in a type should cascade down to all subtypes. In this specific case it's not a big deal ignoring the property on both types. But in bigger content-models, this quickly becomes tedious, if the property to ignore is high up in the hierarchy.

property<> require a resolver

I'm trying give a property a description like this

        type<Image> {
            property<Int>("width") {
                description = "Width of image in pixels"
            }
        }

but get a lateinit property functionWrapper has not been initialized exception.

The only way I get around the problem is to add a simple resolver like this

        type<Image> {
            property<Int>("width") {
                description = "Width of image in pixels"
                resolver { it -> it.width }
            }
        }

Am I doing anything wrong? Is there an easier way to give a property a description?

Variables usage

Hello!

Thank you for this library! Just one question regarding to the variables I'd like to use within my queries. Do you have any example of this usage?

I tried and I failed every time. This line https://github.com/pgutkowski/KGraphQL/blob/master/src/main/kotlin/com/github/pgutkowski/kgraphql/schema/execution/ParallelRequestExecutor.kt#L56 is taking the variables from the Operation and not from the JsonVariables. I couldn't find a way to declare them in the operation in the schema definition itself of passing the right arguments in the schema.execute function.

If you have any code examples with some JSON too as illustration, that would be perfect!

Thank you for your help!

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

release for stable coroutine support

At the moment no version of kgraphql works with non-experimental coroutines
as of now i am unable to update to ktor 1.0.0-beta-1

with 0.3.0-alpha
it does not compile:

Class 'com.github.pgutkowski.kgraphql.schema.Schema' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler

with 0.2.8 it breaks at runtime
kotlinx/coroutines/experimental/CommonPool does not exist

i will attempt to make a PR

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.

Leaking top level

There are a number of variables and functions that are declared at top level and leak through since they are not marked as internal.

An example could be the val OPERANDS = ... in RequestPreProcessing.kt. There are many more.

This pollutes the global scope.

Unable to Query for Description on Type

I have a very simple test class and I've added a description to it in the schema:

data class Player(val name: String = "", val age: Int = 0)

type<Player> {
    description = "A NBA Player on a Team"
}

But when I query for this description with the following:

query {
	__schema {
		types {
	        name
	        kind
	        description
	    }
	}
}

It's always empty. Is there something I need to do differently to be able to inspect the descriptions that I set in the schema?

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.

without mutatons graphiql fails to load schema docs

i am using KGraphQL very similar to tihis sample app https://github.com/adavis/ufo-sightings-api
except i want to have a unmodifiable dataset, so removed all mutations

when loading graphiql this error gets printed

Error: Mutation fields must be an object with field names as keys or a function which returns such an object.
    at invariant (http://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:24809:11)
    at defineFieldMap (http://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:28078:27)
    at GraphQLObjectType.getFields (http://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:28035:44)
    at typeMapReducer (http://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:29752:25)
    at Array.reduce (<anonymous>)
    at new GraphQLSchema (http://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:29641:34)
    at buildClientSchema (http://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:31049:10)
    at http://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:2131:55

and when i add the mutations back in like this

mutation("addNothing") {
    description = "does nothing"

    resolver { input: String -> { println(input)}/**/ }
}

it will error with somethoing about the return value of the resulver in the mutation declaration

Caused by: org.koin.error.BeanInstanceCreationException: Can't create bean Bean[class=moe.nikky.curseproxy.graphql.AppSchema] due to error :
	com.github.pgutkowski.kgraphql.schema.SchemaException: Generic types are not supported by GraphQL, found () -> kotlin.Unit

the introspection query used seems to be

 query IntrospectionQuery {
    __schema {
      queryType { name }
      mutationType { name }
      subscriptionType { name }
      types {
        ...FullType
      }
      directives {
        name
        description
        locations
        args {
          ...InputValue
        }
      }
    }
  }

  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
          ofType {
            kind
            name
            ofType {
              kind
              name
              ofType {
                kind
                name
                ofType {
                  kind
                  name
                }
              }
            }
          }
        }
      }
    }
  }

Extension property not working

I have defined a Site type and added a extension property on top of it like this:

type<Site> {
    property<Boolean>("test") {
        resolver { false }
    }
}

And when trying to query for this field I'm getting: "message": "property test on Site does not exist".

I have tried running this query:

{
  __type(name:"Site") {
    fields {
      name
      type {
        ofType {
          name
        }
}}}}

And I do see that test is in there and is a boolean.

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.

LocalDate when passed as query variable

Hi,

If I do

query getNewInventoryQuery($vin: String!, $fromDate: LocalDate!) {

   parts: getInventory(stockNumber :"XXX-2343-1", fromDate: $fromDate){
    		restockDate
    		stockNumber
        parts {
          oem
          addedDate
          manufacturer
          name
        }
  }
}

and the query variable is:

{
  "vin": "4T3BK3BB1CU070903",
  "fromDate": "1999-12-12"
}

I get :

{ "errors": { "message": "Caught ExecutionException: Failed to coerce 1999-12-12 as java.time.LocalDate" } }

However, if I do not pass the LocalDate and hard code it as :

query getNewInventoryQuery($vin: String!, $fromDate: LocalDate!) {

   parts: getInventory(stockNumber :"XXX-2343-1", fromDate: "1999-12-12"){
    		restockDate
    		stockNumber
        parts {
          oem
          addedDate
          manufacturer
          name
        }
  }
}

the query works.

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

[Idea] Support multi-platform targeting

Kotlin is now multi-platform (JVM/JavaScript/Native).

Currently the project can only target JVM. It would be nice to support the others platforms as well.

Do you you think it's relevant?

Standardizing resolver inputs?

Graphql-js resolvers have the following syntax:
(Source, Args, Context, Info) -> T

Graphql-java resolvers get passed a DataFetchingEnvironment that has all of the above (Source, Args, etc) as properties. So its syntax is:
(DataFetchingEnvironment) -> T

Might be a good idea to standardize the syntax to one of the above.

I suggest:
fun resolver (fetch: suspend (Source, Args, Context, Info) -> T)

Potential Benefits:

  1. It allows an unlimited number of arguments.
  2. It exposes the "Info" of a field/request - such as whether the current operation is a Query or Mutation, and what the field name is. One use case is that you can enable caching when the operation is a Query, and disable it when the operation is a Mutation.
  3. It allows more complicated resolvers, such as dealing with suspend functions.
  4. Forward compatibility with the reference implementation.

Line Graph

Hello,
Below is my JSON output. Can I plot line graph using KGraphQL? If your response is YES then what are all the libraries that I need to include in my project.

private var jsonStringArray = "[{"dailyrate":"2018-09-01","usercount":33},{"dailyrate":"2018-09-02","usercount":44},{"dailyrate":"2018-09-03","usercount":23},{"dailyrate":"2018-09-04","usercount":77}] "

Quotes within argument string not supported

If value for a parameter contains escaped quoted, then the query fails because of failure in parsing the request. The error varies depending on what follows the quoted value, I think quotes are not handled properly:
https://github.com/pgutkowski/KGraphQL/blob/master/src/main/kotlin/com/github/pgutkowski/kgraphql/request/RequestPreProcessing.kt#L24

Example:

{
     hello(name : "Ted\" Mosby")
}

However, passing such strings using query variables works perfectly fine.

Roadmap?

Hi, what's needed for a proper 1.0 release?

A proper roadmap would be great to motivate people and formalize requirements.

Print Schema?

Hi,

Will you be supporting Print Schema as in the graphql-js reference implementation, that generates a schema.graphql document?

Support for suspendable schema execution

Along with #38, it would be great if the schema supported suspendable execute. That way, when using a server that supports coroutines (like ktor with netty), expensive queries and mutations could be suspended naturally with low overhead.

Support for suspendable property resolvers

Would be great with suspendable property resolvers. Something like #37. But something that actually works.

I haven't gotten a full overview of how everything in this project works yet, so I failed implementing this. If there is anything I can help out with I would love to.

Subscription support

In the wiki you mention that it's not supported yet.

Is it desired/anyone working on it? It's something I'd like - and might be able to start work on at some point.

Create a branch with suspend resolvers support

Currently, KGraphQL does not support suspend resolvers.

Adding support to current master is hard (if even possible) because kotlin 1.2 (current stable version) doesn't support reflection on suspend functions.

Support for this has been added in kotlin 1.3-M2, and it would be nice to have an 'async' branch with support for suspend resolvers, until kotlin 1.3 is out.

Proposed implementation available in PR #21

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.

LocalDate coercion issue

Hi,

I am getting the following error:

{
  "errors": {
    "message": "Caught ExecutionException: Failed to coerce {manufacturer:Joe Bloggs,name:Front bumper,oem:true,addedDate:2001-09-01} as NewPart"
  }
}

If I leave out addedDate then the mutation works as expected.

My code is as follows:

   stringScalar<LocalDate> {
            serialize = { date ->
                logger.info("Serialization of date: $date")
                date.toString() }
            deserialize = { dateString ->
                logger.info("Deserialization of custom scalar type: $dateString")
                LocalDate.parse(dateString) }
            description = "Date in format yyyy-mm-dd"
        }

and

 mutation("addPart") {
            description = "Adds a new part in the parts inventory database"
            resolver { newPart: NewPart ->
                val (name, manufacturer, addedDate, oem) = newPart
                val part = Part(name, manufacturer, LocalDate.now(), oem)
                val repository by kodein.instance<PartsRepository>()

                repository.addPart(part)
            }
        }

       inputType<NewPart>(){
        }

This library is amazingly written.

"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.

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
                            }
                        }
                    }
                }
            }
        }
    }
}

at QueryTest().testedSchema unionProperty("favourite")

Property resolver with context

While it is possible to pass an optional context object to the "execute" function of the Schema which than will be propagated to the "suspendResolver"/"resolver" functions of the "query" block, I have not found a way how this context object gets passed to the property resolvers.

(using version 0.3.0)

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?

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]

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.