graphql-java-codegen - 基于模式驱动构建GraphQL应用程序 Kotlin

基于模式驱动构建GraphQL应用程序 release 4.1.0 即将发布

支持生成Kotlin代码(预览阶段,目前仅支持JVM平台上的Kotlin)。

一个经典示例如下:

schema {
    query: Query
}

type Query {
    hero(episode: Episode) : Character
    human(id : String) : Human
    humans: [Human]
    droid(id: ID!) : Droid
}
enum Episode {
    NEWHOPE
    EMPIRE
    JEDI
}

interface Character {
    id: ID!
    name: String!
    friends: [Character]
    appearsIn: [Episode]!
    secretBackstory : String @deprecated(reason : "We have decided that this is not canon")
}

type Human implements Character {
    id: ID!
    name: String!
    friends: [Character]
    appearsIn: [Episode]!
    homePlanet: String
    secretBackstory : String @deprecated(reason : "We have decided that this is not canon")
    email: Email
}

type Droid implements Character {
    id: ID!
    name: String!
    friends: [Character]
    appearsIn: [Episode]!
    primaryFunction: String
    secretBackstory : String @deprecated(reason : "We have decided that this is not canon")
}

scalar Email

本次生成代码如下:
类型(type)
枚举(enum)
返回体(response)
返回体投影(response projection)
请求体(request)
操作(operations/resolver)
在这里插入图片描述
根据生成的代码,实现resolver接口即可。(创建默认的resolver实现的PR不被接受,所以只能一个个实现它了)
其中QueryResolver是个聚合接口,包含所有操作(每个操作对应一个服务端接口)

package io.github.dreamylost

import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.module.kotlin.jsonMapper
import com.fasterxml.jackson.module.kotlin.kotlinModule
import com.fasterxml.jackson.module.kotlin.readValue
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLRequest
import io.github.dreamylost.api.QueryResolver
import io.github.dreamylost.model.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody

/**
 * Server example at https://github.com/jxnu-liguobin/springboot-examples/tree/master/graphql-complete
 * (only a normal graphql server implement by java )
 * @author 梦境迷离
 * @version 1.0,2020/12/14
 */
class QueryResolverImpl : QueryResolver {

    override fun hero(episode: EpisodeTO?): CharacterTO? {
        val heroQueryRequest = HeroQueryRequest()
        heroQueryRequest.setEpisode(episode)
        # 包含所有字段,递归类型的递归深度为3
        val characterResponseProjection = CharacterResponseProjection().`all$`(3)
        val graphQLRequest = GraphQLRequest(heroQueryRequest, characterResponseProjection)
        val ret = getResponse<HeroQueryResponse>(graphQLRequest)
        return ret.hero()
    }

    override fun human(id: String?): HumanTO? {
        val humanQueryRequest = HumanQueryRequest()
        humanQueryRequest.setId(id)
        val humanResponseProjection = HumanResponseProjection().`all$`(1)
        val graphQLRequest = GraphQLRequest(humanQueryRequest, humanResponseProjection)
        val ret = getResponse<HumanQueryResponse>(graphQLRequest)
        return ret.human()
    }

    override fun humans(): List<HumanTO?>? {
        val humanQueryRequest = HumansQueryRequest()
        val humanResponseProjection = HumanResponseProjection().`all$`(1)
        val graphQLRequest = GraphQLRequest(humanQueryRequest, humanResponseProjection)
        val ret = getResponse<HumansQueryResponse>(graphQLRequest)
        return ret.humans()
    }

    override fun droid(id: String): DroidTO? {
        val productByIdQueryRequest = DroidQueryRequest()
        productByIdQueryRequest.setId(id)
        val droidResponseProjection = DroidResponseProjection().`all$`(1)
        val graphQLRequest = GraphQLRequest(productByIdQueryRequest, droidResponseProjection)
        val ret = getResponse<DroidQueryResponse>(graphQLRequest)
        return ret.droid()
    }
}

inline fun <reified T> getResponse(request: GraphQLRequest, url: String = "http://localhost:8080/graphql"): T {
    val json = "application/json; charset=utf-8".toMediaTypeOrNull()
    val body = request.toHttpJsonBody().toRequestBody(json)
    val client = OkHttpClient()
    val request = Request.Builder().post(body).url(url).build()
    val call = client.newCall(request)
    return Jackson.mapper.readValue<T>(call.execute().body!!.string())
}

object Jackson {
    val mapper = jsonMapper {
        addModule(kotlinModule())
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        serializationInclusion(JsonInclude.Include.NON_ABSENT)
        serializationInclusion(JsonInclude.Include.NON_NULL)
    }

}

gradle配置如下

import com.kobylynskyi.graphql.codegen.model.GeneratedLanguage
import io.github.kobylynskyi.graphql.codegen.gradle.GraphQLCodegenGradleTask

plugins {
    id 'java'
    id "org.jetbrains.kotlin.jvm" version "1.3.71"
    id "io.github.kobylynskyi.graphql.codegen" version "4.0.2-SNAPSHOT"
}

group 'io.github.dreamylost'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

sourceSets {
    main.kotlin.srcDirs += "$buildDir/generated-server"
}

repositories {
    maven {
        url 'https://repo.gradle.org/gradle/libs-releases-local'
    }
    mavenCentral()
    mavenLocal()
    jcenter()
}


dependencies {
    implementation "io.github.kobylynskyi:graphql-java-codegen:4.0.2-SNAPSHOT"
    implementation "javax.validation:validation-api:2.0.1.Final"
    implementation("com.squareup.okhttp3:okhttp:4.2.2")
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.12.0'
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.12.0'
    compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.12.0'
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.12.0'
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

/**
 * Generate apis and models in Kotlin
 */
compileKotlin.dependsOn "graphqlCodegenKotlinService"
sourceSets.main.java.srcDir "$buildDir/generated-server"
task graphqlCodegenKotlinService(type: GraphQLCodegenGradleTask) {
    graphqlSchemas.includePattern = "schema\\.graphqls"
    outputDir = new File("$buildDir/generated-server")
    generateClient = true
    generateApis = true
    generatedLanguage = GeneratedLanguage.KOTLIN
    generateBuilder = false
    generateImmutableModels = true
    apiPackageName = "io.github.dreamylost.api"
    modelPackageName = "io.github.dreamylost.model"
    customAnnotationsMapping = [
            "Character": ["@com.fasterxml.jackson.annotation.JsonTypeInfo(use=com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME, include=com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY,property = \"__typename\")",
                          "@com.fasterxml.jackson.annotation.JsonSubTypes(value = arrayOf(" + System.lineSeparator() +
                                  "       com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = HumanTO::class, name = \"Human\"), " + System.lineSeparator() +
                                  "       com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = DroidTO::class, name = \"Droid\")))"],
    ]
    modelNameSuffix = "TO"
}

使用

class QueryResolverMain {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val queryResolverImpl = QueryResolverImpl()
            println("r1")
            val r1 = queryResolverImpl.droid("2001")
            println(r1)
            println("r2")
            val r2 = queryResolverImpl.humans()
            println(r2)
            println("r3")
            val r3 = queryResolverImpl.hero(EpisodeTO.EMPIRE)
            println(r3)
            println("r4")
            val r4 = queryResolverImpl.human("1002")
            println(r4)

        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值