pgutkowski / kgraphql Goto Github PK
View Code? Open in Web Editor NEWPure Kotlin GraphQL implementation
License: MIT License
Pure Kotlin GraphQL implementation
License: MIT License
I have a class with a property who's type is BigInt
which Kotlin does not currently support reflection on. I'm curious if there is a work around for these scenarios?
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!
Interesting approach!
I can't find in the examples: does KGraphQL support resolvers on user types? (not just query and mutation)
Hi,
Will you be supporting Print Schema as in the graphql-js reference implementation, that generates a schema.graphql document?
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.
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?
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.
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.
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?
Error: Invalid or incomplete schema, unknown type: Favourite. Ensure that a full introspection query is used in order to build a client schema.
at getNamedType (https://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:30861:13)
at getType (https://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:30852:12)
at getOutputType (https://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:30875:16)
at https://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:30996:15
at https://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:24939:31
at Array.reduce ()
at keyValMap (https://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:24938:15)
at buildFieldDefMap (https://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:30990:36)
at fields (https://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:30939:16)
at resolveThunk (https://cdn.jsdelivr.net/npm/[email protected]/graphiql.js:27896:40)
It should be possible to use suspendable unionproperty resolvers also.
With a few more lines of code, this should be possible to fix alongside #38
What is dsl?
It provides rich DSL to setup GraphQL schema ...
The readme says 1.3.x compiler is required, but then says to add the 1.2.x version to the buildscript
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.
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
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.
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
}
}
}
}
}
}
}
}
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.
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 :)
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.
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}] "
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.
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?
Hi, what's needed for a proper 1.0 release?
A proper roadmap would be great to motivate people and formalize requirements.
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.
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
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!
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.
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.
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?
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.
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.
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.
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
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.
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]
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)
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:
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?
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
}
}
}
}
}
}
}
}
Other GraphQL libraries allow the definition of custom scalar types.
http://dev.apollodata.com/tools/graphql-tools/scalars.html#Date-as-a-scalar as an example.
It would be awesome to get this feature also for KGraphQL!
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
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.
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
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.