当前位置: 代码迷 >> 综合 >> graphql-java-codegen - 基于模式驱动构建GraphQL应用程序 Kotlin
  详细解决方案

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

热度:93   发布时间:2023-09-23 10:11:26.0

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

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

一个经典示例如下:

schema {query: Query
}type Query {hero(episode: Episode) : Characterhuman(id : String) : Humanhumans: [Human]droid(id: ID!) : Droid
}
enum Episode {NEWHOPEEMPIREJEDI
}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: StringsecretBackstory : 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: StringsecretBackstory : String @deprecated(reason : "We have decided that this is not canon")
}scalar Email

本次生成代码如下:
类型(type)
枚举(enum)
返回体(response)
返回体投影(response projection)
请求体(request)
操作(operations/resolver)
graphql-java-codegen - 基于模式驱动构建GraphQL应用程序 Kotlin
根据生成的代码,实现resolver接口即可。(创建默认的resolver实现的PR不被接受,所以只能一个个实现它了)
其中QueryResolver是个聚合接口,包含所有操作(每个操作对应一个服务端接口)

package io.github.dreamylostimport 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)# 包含所有字段,递归类型的递归深度为3val 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.GraphQLCodegenGradleTaskplugins {
    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.8sourceSets {
    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 = truegenerateApis = truegeneratedLanguage = GeneratedLanguage.KOTLINgenerateBuilder = falsegenerateImmutableModels = trueapiPackageName = "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 {
    @JvmStaticfun 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)}}
}
  相关解决方案