-
Notifications
You must be signed in to change notification settings - Fork 4
Overview of generated GraphQL DSL
Let's take a look at a DSL generated from a simple GraphQL schema (file example.graphqls
):
type Query {
filmCount: Int!
}
By our schema file example.graphqls
Kobby will generate Kotlin file example.kt
(more about entry point configuration
see here):
public fun exampleContextOf(adapter: ExampleAdapter): ExampleContext = ExampleContextImpl(adapter)
public interface ExampleContext {
public suspend fun query(__projection: QueryProjection.() -> Unit): Query
public suspend fun mutation(__projection: MutationProjection.() -> Unit): Mutation
public fun subscription(__projection: SubscriptionProjection.() -> Unit):
ExampleSubscriber<Subscription>
}
// ... skipped
The ExampleContext
interface is an entry point to generated client DSL. It contains three functions - query
, mutation
and subscription
- which provide the ability to perform the corresponding GraphQL operations. Our
schema example.graphqls
only defines a Query
type, so the generated mutations and subscriptions are dummy. But the
query function allows us to create and execute real GraphQL queries according to our schema. Let's try to execute a
simple query and get a response.
First, we have to build our query:
query {
filmCount
}
The query function argument __projection
is responsible for building the query. It has a Kotlin lambda type
with QueryProjection
receiver:
public suspend fun query(__projection: QueryProjection.() -> Unit): Query
The QueryProjection
is an interface, defined in entity/Query.kt
file:
@ExampleDSL
public interface QueryProjection {
public fun filmCount(): Unit
}
This "projection" interface allows us to write a query with syntax very similar to GraphQL's native syntax:
fun main() = runBlocking {
val context: ExampleContext = exampleContextOf(createMyAdapter())
val response: Query = context.query {
filmCount()
}
}
fun createMyAdapter(): ExampleAdapter =
TODO("Let's look at adapters later")
We have used the exampleContextOf
function, defined in example.kt
file, to instantiate the ExampleContext
interface. And then we called the query
function to build the GraphQL query and get the response to the query.
The response to our query is JSON, that looks like:
{
"data": {
"filmCount": 25
}
}
To represent the response, Kobby generates an "entity" interface, that holds the response data. For our GraphQL Query
type, defined in the schema, the corresponding "entity" interface is the Query
interface defined in entity/Query.kt
file (just before the QueryProjection
interface):
public interface Query : ExampleContext {
public val filmCount: Int
}
The Query
interface has the filmCount
property that contains the value of the filmCount
attribute in our JSON
response:
val response: Query = context.query {
filmCount()
}
println("Film count: ${response.filmCount}")
Note, that the Query
interface extends ExampleContext
interface. So, every "entity" interface that Kobby generates
is an entry point for new GraphQL queries, mutations, and subscriptions. This enables us to use
Kotlin extension functions for smart customization of the generated DSL.