https://kotlinlang.org logo
#feed
Title
# feed
d

Dariusz Kuc

11/05/2019, 3:20 PM
Hello! We just published a first story in a series that highlights different parts of
graphql-kotlin
library. Post today highlights how
graphql-kotlin-schema-generator
can be used to generate your GraphQL schemas directly from your source code - https://medium.com/expedia-group-tech/creating-graphql-schemas-in-kotlin-aaaac0ab0672 Stay tuned for the next posts in the series that will highlight federation and spring server modules!
👍 6
s

Stephan Schroeder

11/06/2019, 9:47 AM
I defined some extension functions to make the Java-way more Kotlin idiomatic:
Copy code
private inline fun <reified O, A:Any> dataFetcherByArgument(
    argumentName: String,
    crossinline transform: (A)->O
): DataFetcher<O> =  DataFetcher<O>
{ dataFetchingEnvironment ->
    val argument: A = dataFetchingEnvironment.getArgument(argumentName)
    transform(argument)
}

private inline fun <reified O, S:Any> dataFetcherBySource(
    crossinline transform: (S)->O
): DataFetcher<O> =  DataFetcher<O> { dataFetchingEnvironment ->
    val source: S = dataFetchingEnvironment.getSource()
    transform(source)
}

private fun RuntimeWiring.Builder.addTypeWiring(graphQLType: String, fieldName: String, dataFetcher: DataFetcher<*>) {
    this.type(newTypeWiring(graphQLType).dataFetcher(fieldName, dataFetcher))
}
with that explicit configuration is pretty straight forward and takes up less space
Copy code
@Configuration
class GraphQLProvider(
    val offerService: OfferService,
    val offerDetailService: OfferDetailService
) {

    @Bean
    fun graphQL(): GraphQL {
        val sdl = ClassPathResource("schema.graphqls").inputStream.reader().readText()
        val graphQLSchema = SchemaGenerator().makeExecutableSchema(
                SchemaParser().parse(sdl),
                buildWiring()
        )
        return GraphQL.newGraphQL(graphQLSchema).build()
    }

    private fun buildWiring(): RuntimeWiring = RuntimeWiring.newRuntimeWiring().apply {
        addTypeWiring("Query", "status", DataFetcher<String> { "up and running" })
        addTypeWiring("Query", "offerById", dataFetcherByArgument( "offerId" ) {argument: String ->
            offerService.getOfferBy(argument.toLong())
        })
        addTypeWiring("Offer", "offerDetail", dataFetcherBySource { offer: Offer ->
            offerDetailService.getOfferDetailBy(offer.offerDetailId)
        })
    }.build()
}
The formating looks better when not crammed into a discussion-collumn 😅
d

Dariusz Kuc

11/06/2019, 1:09 PM
in the above you are still following SDL first approach of explicitly loading schema and then manually creating the wirings for the field resolvers, with
graphql-kotlin
you would simply create
Copy code
class MyQueries(private val offerService: OfferService) {
  val status = "up and running"
  fun offerById(id: String) =  offerService.getOfferBy(id.toLong())
}

class Offer(val offerDetailId: Long, private val offerDetailService: OfferDetailService) {
  fun offerDetail() = offerDetailService.getOfferDetailBy(offerDetailId)
}
s

Stephan Schroeder

11/06/2019, 2:26 PM
What happens if your data model is not a tree but a graph? Like a Book has a List<Author> and each Author has written a List<Book>. It looks like your GraphQL schema is a 1-to-1 representation of the object model, in which case I’d assume that graphs are a problem?
d

Dariusz Kuc

11/06/2019, 3:07 PM
you can certainly express it as
Copy code
class Book(val authors: List<Author>)
class Author(val books: List<Book>)
s

Stephan Schroeder

11/07/2019, 10:57 AM
1) yes, but it’s kind of hard to fill it from the db, if you don’t know how much data the querry actually uses?? I’m quite new do GraphQL, so might simply be wrong here. But that’s what I like about the TypeWiring approach, the backing data model (and therefore graph) can be different to the data model defiened in the schema. It breaks up circular dependencies. 2) now a completely different - but related - GraphQL question: any tipps about which approach/library to use for a GraphQL client? I only need the client for our integration tests, so I’m looking for a Jva/Kotlin solution. The default pick seems to be appollo-android, even though I’m not developing for android (but serverside JVM with Spring Boot), but we use gradle which seems to be a dependency. This article https://blog.getantler.io/graphql-java-client/ claims that the whole graphql-client field is still underdeveloped (in March 2019) as soon as you leave the mobile/js environment and advocates for doing it yourself via direct json-processing. What would you recommend?
d

Dariusz Kuc

11/07/2019, 2:30 PM
re: 1 - you could still easily do the same - e.g. write a function in
Author
that return
Book
which has a function to return list of
Author
, so you could represent your circular dependencies (but also to be completely honest I'm unsure how useful those are, guess it really depends on your data set)
re: 2 -
apollo-android
is a generic client and its only
android
specific in its name, it can be easily used on the server side. Also that linked is correct -> JS is currently still the primary environment, your options are fairly limited outside of JS ecosystem. I'd personally go with
apollo-android
as it will give you type safety but you could do even a simple POST. I know some people that also used https://github.com/americanexpress/nodes but personally not a big fan of it.
2 Views