Skip to content

GraphQL Java Kickstart support

dermakov edited this page May 1, 2024 · 3 revisions

NOTE: GraphQL Java Kickstart is not supported since release 4.0.0

Kobby is focused on client-side development but provides little support of server-side GraphQL Java Kickstart library. You can generate resolver interfaces by GraphQL schema by means of Kobby Plugin.

Put your GraphQL schema file in the project resources with graphqls extension. For example, let define cinema.graphqls schema file:

type Query {
    countries(offset: Int! = 0, limit: Int! = 100): [Country!]!
}

type Country {
    id: ID!
    name: String!

    films(offset: Int! = 0, limit: Int! = 100): [Film!]!
}

type Film {
    id: ID!
    title: String!

    country: Country!
}

Add Kobby plugin to your build.gradle.kts, to generate Kotlin DSL (Maven plugin is also available):

repositories {
    mavenLocal()
    mavenCentral()
}

buildscript {
    repositories {
        mavenLocal()
        mavenCentral()
    }
}

plugins {
    kotlin("jvm") version "1.5.21"
    id("io.github.ermadmi78.kobby") version "1.0.0"
}

dependencies {
    // Add this dependency to enable graphql-java-kickstart resolvers generation by Kobby
    compileOnly("com.graphql-java-kickstart:graphql-java-tools:11.0.1")

    // Add this dependency to wrap subscription resolver functions result in org.reactivestreams.Publisher
    compileOnly("org.reactivestreams:reactive-streams:1.0.3")
}

Run gradle clean build, and Kobby will generate resolver interfaces and DTO classes for you:

import graphql.kickstart.tools.GraphQLQueryResolver
import graphql.kickstart.tools.GraphQLResolver

interface CinemaQueryResolver : GraphQLQueryResolver {
    suspend fun countries(offset: Int, limit: Int): List<CountryDto>
}

interface CinemaCountryResolver : GraphQLResolver<CountryDto> {
    suspend fun films(
        country: CountryDto,
        offset: Int,
        limit: Int
    ): List<FilmDto>
}

data class CountryDto(
    val id: Long? = null,
    val name: String? = null,
    val films: List<FilmDto>? = null
)

data class FilmDto(
    val id: Long? = null,
    val title: String? = null,
    val country: CountryDto? = null
)

Kobby generates resolver functions for all fields in root GraphQL types (Query, Mutation and Subscription). For other GraphQL types, Kobby generates resolver functions only for fields with arguments.
For example, for the Country type, Kobby generates the CinemaCountryResolver interface with one films method, but for the Film type, it does not generate a resolver at all.

But sometimes we have to resolve fields without arguments. For example, we have to resolve the country field in the Film type. You can ask Kobby to generate a resolver for this field using the @resolve directive. Let's modify our schema:

directive @resolve on FIELD_DEFINITION

type Query {
    countries(offset: Int! = 0, limit: Int! = 100): [Country!]!
}

type Country {
    id: ID!
    name: String!

    films(offset: Int! = 0, limit: Int! = 100): [Film!]!
}

type Film {
    id: ID!
    title: String!

    country: Country! @resolve
}

And Kobby will generate resolver interface for the Film type:

import graphql.kickstart.tools.GraphQLResolver

interface CinemaFilmResolver : GraphQLResolver<FilmDto> {
    suspend fun country(film: FilmDto): CountryDto
}

Together with the resolver interfaces, Kobby generates the client DSL. If you don't need it, you can disable client generation by means of kobby extension:

plugins {
    kotlin("jvm") version "1.5.21"
    id("io.github.ermadmi78.kobby") version "1.0.0"
}

kobby {
    kotlin {
        dto {
            graphQL {
                // Disable helper DTO classes generation
                enabled = false
            }
        }
        entity {
            // Disable entities generation
            enabled = false
        }
    }
}

The kobby extension also provides additional settings for resolver generation:

kobby {
    kotlin {
        // Configuration of resolver interfaces generation
        resolver {
            // Is resolver interfaces generation enabled
            // By default `true` if `com.graphql-java-kickstart:graphql-java-tools`
            // artifact is in the project dependencies
            enabled = null // Boolean

            // Is wrap subscription resolver functions result in `org.reactivestreams.Publisher`
            // By default `true` if `org.reactivestreams:reactive-streams`
            // artifact is in the project dependencies
            publisherEnabled = null // Boolean

            // Package name for resolver interfaces relative to root package name
            packageName = "resolver"

            // Prefix for resolver interfaces
            // By default is capitalized context name
            prefix = null // String

            // Postfix for resolver interfaces
            postfix = "Resolver"

            // Name for parent object argument
            // By default is de-capitalized name of parent object type
            argument = null // String

            // If not null, Kobby will generate default implementation for
            // functions in resolver interfaces that looks like:
            // TODO("$toDoMessage")
            toDoMessage = null // String
        }
    }
}