未验证 提交 22f1e804 编写于 作者: 梦境迷离's avatar 梦境迷离 提交者: GitHub

Add examples for Scala code (#406)

* add example-client-scala for scala code

* add example-client-scala for scala code
上级 2736c2e4
......@@ -20,6 +20,9 @@ addSbtPlugin("io.github.jxnu-liguobin" % "graphql-codegen-sbt-plugin" % "<versio
//since graphql-java-codegen V2.2.1
```
> Java code will be generated by default, via set `generatedLanguage =: GeneratedLanguage.SCALA` to generate Scala code(since 4.0.0)
> By the way, Scala code is currently ugly.
### Config
......@@ -66,6 +69,58 @@ customAnnotationsMapping := {
}
```
### Config(generate scala code)
```scala
import java.util
name := "example-client-scala"
organization := "io.github.jxnu-liguobin"
libraryDependencies ++= Seq(
"org.apache.logging.log4j" %% "log4j-api-scala" % "11.0",
"org.apache.logging.log4j" % "log4j-api" % "2.8.2",
"org.apache.logging.log4j" % "log4j-core" % "2.8.2",
"org.apache.logging.log4j" % "log4j-slf4j-impl" % "2.8.2",
"com.squareup.okhttp3" % "okhttp" % "4.7.2",
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.11.3",
"com.fasterxml.jackson.core" % "jackson-databind" % "2.11.3",
"org.json" % "json" % "20190722")
enablePlugins(GraphQLCodegenPlugin)
graphqlJavaCodegenVersion := Some("4.0.1-SNAPSHOT")
GraphQLCodegenPluginDependencies
graphqlSchemaPaths := List("src/main/resources/schema.graphqls")
modelPackageName := Some("io.github.dreamylost.model")
apiPackageName := Some("io.github.dreamylost.api")
generateClient := true
generateApis := true
//TODO wrap it in plugin maybe better? after wrapping, them import automatically
generatedLanguage := com.kobylynskyi.graphql.codegen.model.GeneratedLanguage.SCALA
generateImmutableModels := true
modelNameSuffix := Some("DO")
customAnnotationsMapping := {
// in the future, maybe wrap it by scala coolection
val mapping = new util.HashMap[String, util.List[String]]
val annotations = new util.ArrayList[String]()
annotations.add("@com.fasterxml.jackson.annotation.JsonTypeInfo(use=com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME, include=com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY,property = \"__typename\")")
annotations.add(
"""@com.fasterxml.jackson.annotation.JsonSubTypes(value = Array(
| new com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = classOf[HumanDO], name = "Human"),
| new com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = classOf[DroidDO], name = "Droid")))""".stripMargin)
mapping.put("Character", annotations)
// please pay attention here, codegen have not generated `EpisodeDOEnum.scala` class, so you should create it.
mapping.put("Droid.appearsIn", util.Arrays.asList("@com.fasterxml.jackson.module.scala.JsonScalaEnumeration(classOf[io.github.dreamylost.EpisodeDOEnum])"))
mapping.put("Human.appearsIn", util.Arrays.asList("@com.fasterxml.jackson.module.scala.JsonScalaEnumeration(classOf[io.github.dreamylost.EpisodeDOEnum])"))
mapping
}
generateCodegenTargetPath in GraphQLCodegenConfig := crossTarget.value / "src_managed_graphql_scala"
generateEqualsAndHashCode := true
generateToString := true
```
### Codegen Options
......
......@@ -92,7 +92,7 @@ trait GraphQLCodegenKeys {
//use different paths
val graphqlSchemaValidate = inputKey[Seq[String]]("graphqlSchemaValidatePaths")
val graphqlCodegen = taskKey[Seq[File]]("Generate Java code")
val graphqlCodegen = taskKey[Seq[File]]("Generate code")
val graphqlCodegenValidate = taskKey[Unit]("Validate graphql schema")
......@@ -120,6 +120,6 @@ trait GraphQLCodegenKeys {
val javaxValidationApiVersion = settingKey[Option[String]]("javax-validation-api version")
val graphqlJavaCodegenVersion = settingKey[Option[String]]("graphql java codegen version")
val generateCodegenTargetPath = settingKey[File]("The path for graphqlCodegen to save java code which generate by plugin")
val generateCodegenTargetPath = settingKey[File]("The path for graphqlCodegen to save code which generate by plugin")
}
import java.util
name := "example-client-scala"
organization := "io.github.jxnu-liguobin"
libraryDependencies ++= Seq(
"org.apache.logging.log4j" %% "log4j-api-scala" % "11.0",
"org.apache.logging.log4j" % "log4j-api" % "2.8.2",
"org.apache.logging.log4j" % "log4j-core" % "2.8.2",
"org.apache.logging.log4j" % "log4j-slf4j-impl" % "2.8.2",
"com.squareup.okhttp3" % "okhttp" % "4.7.2",
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.11.3",
"com.fasterxml.jackson.core" % "jackson-databind" % "2.11.3",
"org.json" % "json" % "20190722")
enablePlugins(GraphQLCodegenPlugin)
graphqlJavaCodegenVersion := Some("4.0.1-SNAPSHOT")
GraphQLCodegenPluginDependencies
graphqlSchemaPaths := List("src/main/resources/schema.graphqls")
modelPackageName := Some("io.github.dreamylost.model")
apiPackageName := Some("io.github.dreamylost.api")
generateClient := true
generateApis := true
//TODO wrap it in plugin maybe better? after wrapping, them import automatically
generatedLanguage := com.kobylynskyi.graphql.codegen.model.GeneratedLanguage.SCALA
generateImmutableModels := true
modelNameSuffix := Some("DO")
customAnnotationsMapping := {
// in the future, maybe wrap it by scala coolection
val mapping = new util.HashMap[String, util.List[String]]
val annotations = new util.ArrayList[String]()
annotations.add("@com.fasterxml.jackson.annotation.JsonTypeInfo(use=com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME, include=com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY,property = \"__typename\")")
annotations.add(
"""@com.fasterxml.jackson.annotation.JsonSubTypes(value = Array(
| new com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = classOf[HumanDO], name = "Human"),
| new com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = classOf[DroidDO], name = "Droid")))""".stripMargin)
mapping.put("Character", annotations)
// Please pay attention here, codegen have not generated `EpisodeDOEnum.scala` class, so you should create it.
mapping.put("Droid.appearsIn", util.Arrays.asList("@com.fasterxml.jackson.module.scala.JsonScalaEnumeration(classOf[io.github.dreamylost.EpisodeDOEnum])"))
mapping.put("Human.appearsIn", util.Arrays.asList("@com.fasterxml.jackson.module.scala.JsonScalaEnumeration(classOf[io.github.dreamylost.EpisodeDOEnum])"))
mapping
}
generateCodegenTargetPath in GraphQLCodegenConfig := crossTarget.value / "src_managed_graphql_scala"
generateEqualsAndHashCode := true
generateToString := true
\ No newline at end of file
addSbtPlugin("io.github.jxnu-liguobin" % "graphql-codegen-sbt-plugin" % "4.0.1-SNAPSHOT")
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{ISO8601}] [%-5p] [%t#%T] %c#%L - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="io.github" level="info" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
\ No newline at end of file
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
package io.github.dreamylost
import com.fasterxml.jackson.core.`type`.TypeReference
import io.github.dreamylost.model.EpisodeDO
class EpisodeDOEnum extends TypeReference[EpisodeDO.type]
package io.github.dreamylost
import com.fasterxml.jackson.annotation.JsonInclude.Include
import com.fasterxml.jackson.databind.{ DeserializationFeature, ObjectMapper }
import com.fasterxml.jackson.module.scala.{ DefaultScalaModule, ScalaObjectMapper }
object Jackson {
lazy val mapper: ObjectMapper with ScalaObjectMapper = {
val mapper = new ObjectMapper() with ScalaObjectMapper
mapper.setSerializationInclusion(Include.NON_NULL)
mapper.setSerializationInclusion(Include.NON_ABSENT)
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
mapper.registerModule(DefaultScalaModule)
mapper
}
}
package io.github.dreamylost
import java.io.IOException
import java.util
import java.util.concurrent.TimeUnit
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLRequest
import okhttp3._
import scala.concurrent.{ ExecutionContext, Future, Promise }
object OkHttp {
var url = "http://localhost:8080/graphql"
val defaultCharset = "utf8"
val json = MediaType.parse("application/json; charset=utf-8")
private lazy val defaultTimeout: Long = TimeUnit.MINUTES.toMillis(1)
lazy val client: OkHttpClient = buildClient(defaultTimeout, defaultTimeout, defaultTimeout)
def buildClient(readTimeout: Long, writeTimeout: Long, connectTimeout: Long): OkHttpClient = {
new OkHttpClient.Builder()
.readTimeout(readTimeout, TimeUnit.MILLISECONDS)
.writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.protocols(util.Arrays.asList(Protocol.HTTP_1_1, Protocol.HTTP_2))
.build()
}
/**
*
* @param request
* @param ec
* @tparam T
* @return
*/
def executeRequest[T: Manifest](request: GraphQLRequest)(implicit ec: ExecutionContext): Future[T] = {
val rb = new Request.Builder().url(url).addHeader("Accept", "application/json; charset=utf-8").
post(RequestBody.create(request.toHttpJsonBody, json))
val promise = Promise[T]
println("Graphql query " + request.toHttpJsonBody)
OkHttp.client.newCall(rb.build()).enqueue(new Callback {
override def onFailure(call: Call, e: IOException): Unit = {
promise.failure(e)
}
override def onResponse(call: Call, response: Response): Unit = {
if (response.isSuccessful) {
val result = parseFrom[T](response.body().string())
promise.success(result.asInstanceOf[T])
} else {
Future.successful()
}
}
})
promise.future
}
def parseFrom[T: Manifest](json: String): T = Jackson.mapper.readValue(json)
}
package io.github.dreamylost.service
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLRequest
import io.github.dreamylost.api.QueryResolver
import io.github.dreamylost.model._
import io.github.dreamylost.OkHttp
import io.github.dreamylost.model.EpisodeDO.EpisodeDO
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
/**
* This is scala style deserialization
*
* @author liguobin@growingio.com
* @version 1.0,2020/11/27
*/
class QueryResolverImpl extends QueryResolver {
@throws[Exception]
def hero(episode: EpisodeDO): CharacterDO = {
val heroQueryRequest = new HeroQueryRequest
heroQueryRequest.setEpisode(episode)
val characterResponseProjection = new CharacterResponseProjection().all$(1)
val graphQLRequest = new GraphQLRequest(heroQueryRequest, characterResponseProjection)
val retFuture = OkHttp.executeRequest[HeroQueryResponse](graphQLRequest)
val ret = Await.result(retFuture, Duration.Inf)
ret.hero()
}
@throws[Exception]
def human(id: String): HumanDO = {
val humanQueryRequest = new HumanQueryRequest
humanQueryRequest.setId(id)
val humanResponseProjection = new HumanResponseProjection().all$(1)
val graphQLRequest = new GraphQLRequest(humanQueryRequest, humanResponseProjection)
val retFuture = OkHttp.executeRequest[HumanQueryResponse](graphQLRequest)
val ret = Await.result(retFuture, Duration.Inf)
ret.human()
}
@throws[Exception]
def humans: Seq[HumanDO] = {
val humanQueryRequest = new HumansQueryRequest
val humanResponseProjection = new HumanResponseProjection().all$(1)
val graphQLRequest = new GraphQLRequest(humanQueryRequest, humanResponseProjection)
val retFuture = OkHttp.executeRequest[HumansQueryResponse](graphQLRequest)
val ret = Await.result(retFuture, Duration.Inf)
ret.humans()
}
@throws[Exception]
def droid(id: String): DroidDO = {
val productByIdQueryRequest = new DroidQueryRequest
productByIdQueryRequest.setId(id)
val droidResponseProjection = new DroidResponseProjection().all$(1)
val graphQLRequest = new GraphQLRequest(productByIdQueryRequest, droidResponseProjection)
val retFuture = OkHttp.executeRequest[DroidQueryResponse](graphQLRequest)
val ret = Await.result(retFuture, Duration.Inf)
ret.droid()
}
}
package io.github.dreamylost.service
import io.github.dreamylost.model.EpisodeDO
/**
*
* @author liguobin@growingio.com
* @version 1.0,2020/7/21
*/
object QueryResolverImplMain extends App {
val droidResolver = new QueryResolverImpl
println("=======QueryResolverImpl=======")
// need typename on Projection
println("=======get droid id 2001=========")
val d = droidResolver.droid("2001")
println(d)
println("=======get humans all=======")
val hums = droidResolver.humans
for (h <- hums) {
println(h)
}
println("=======get human id 1002=======")
val hum = droidResolver.human("1002")
println(hum)
println("=======get hero Episode.EMPIRE=======")
val character = droidResolver.hero(EpisodeDO.EMPIRE)
println(character)
println("=======QueryResolverImpl2=======")
/**
* MAX DEPTH = 4
* gql:{{{
* { id name friends {
* id name friends {
* id name friends {
* id name friends {
* id name friends {
* id name appearsIn secretBackstory __typename }
* appearsIn secretBackstory __typename }
* appearsIn secretBackstory __typename }
* appearsIn secretBackstory __typename }
* appearsIn secretBackstory __typename }
* appearsIn primaryFunction secretBackstory __typename }
* }}}
*/
val droidResolver2 = new QueryResolverImpl
println("=======2get droid id 2001=========")
val d2 = droidResolver2.droid("2001")
println(d2)
println("=======2get humans all=======")
val hums2 = droidResolver2.humans
for (h <- hums2) {
println(h)
}
println("=======2get human id 1002=======")
val hum2 = droidResolver2.human("1002")
println(hum2)
println("=======2get hero Episode.EMPIRE=======")
val character2 = droidResolver2.hero(EpisodeDO.EMPIRE)
println(character2)
}
# check if the file gets created
> graphqlCodegen
> graphqlSchemaValidate src/main/resources/schema.graphqls
> graphqlCodegenValidate
> compile
$ exists target/scala-2.12/src_managed_graphql_scala/io/github/dreamylost/model/CharacterDO.scala
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册