Writing a GraphQL DSL in Kotlin
Tags: dsl, graphql, kotlin
Published: 2019-03-18 12:44:09

---
title: Writing a GraphQL DSL in Kotlin
published: true
tags: dsl,graphql,kotlin
canonical_url: https://alediaferia.com/2019/03/18/writing-graphql-dsl-kotlin/
cover_image: https://alediaferia.com/wp-content/uploads/2019/03/graphql-kotlin-2.png
---

I’ve recently spent some time testing a GraphQL endpoint against a few queries. At the moment I’m keeping my queries as multi-line strings but I was wondering:

> How hard would it be to build a GraphQL query DSL in Kotlin?

I thought this could be a good opportunity to become more familiar with Kotlin DSL capabilities.

Here’s what I’ve got so far.

```kotlin
query("theQuery") { 
    "allUsers"("type" to "users", "limit" to 10) {
        select("name")
        select("address") {
            select("city")
            select("street"("postCode" to true))
        } 
    }
}
```

The above snippet produces the following result:

```graphql
query theQuery {
    allUsers(type: "users", limit: 10) { 
        name
        address { 
            city 
            street(postCode: true)
        }
    }
}
```

The main challenges I have faced up to this point have been around supporting:

- any string to be used as the root field of the query (e.g.`"allUsers"`)
- nested selection of fields
- a map-like syntax for field arguments (I’ve settled for the `to` method for now)

## Any String is a Field

As you can see from the above example, it is possible to start the root field declaration using a string, followed by the fields selection:

```kotlin
"allUsers" { 
    select("name") 
    select("title")
}
```

I’ve achieved that thanks to the [Invoke operator overloading](https://kotlinlang.org/docs/reference/operator-overloading.html#invoke) support. Read on to find out how I have implemented it.

### String.invoke to the rescue

The incredibly powerful [extensions support](https://kotlinlang.org/docs/reference/extensions.html) helps me define my own implementation of `invoke` on a `String`.

```kotlin
operator fun String.invoke(block: Field.Builder.() -> Unit) = Field.Builder().apply { this@apply.block() }.withName(this)
```

This way, any String instance can be turned into a `Field.Builder` by passing a block to the `invoke` operator `()`. Additionally, Kotlin’s compact syntax, saves us from having to explicitly use the open and close parenthesis, making the result a little more readable.

## Select-ing sub-fields

```kotlin
"allUsers" { 
    select("name") 
    select("title")
}
```

Inside the declared root field, a sequence of `select` instructions informs the current field builder about which sub-fields we are interested in. The way this is achieved is by letting the compiler know that we are in the context of a `Field.Builder` and that any method specified in the block has to be resolved against it. This is possible thanks to _function literals with receiver_.

### _Function literals with receiver_

This is probably the most useful feature Kotlin has to offer when it comes to building DSLs.

```kotlin
operator fun String.invoke(block: Field.Builder.() -> Unit)
```

The block argument has been declared as `Field.Builder.() -> Unit`.  
As we can see from the docs:

> […] Kotlin provides the ability [to call an instance](https://kotlinlang.org/docs/reference/lambdas.html#invoking-a-function-type-instance) of a function type with receiver providing the _receiver object_.
> 
> <cite><a href="https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver">Function literals with receiver – Kotlin reference</a></cite>

What this means is that I can invoke the `block` having the current `Field.Builder` instance as receiver resulting in the `select` invocations to be being resolved against it.

## Field arguments

When it comes to specifying field arguments, I’ve had to settle for that not-so-pretty to syntax.

```kotlin
"type" to "users", "limit" to 10
```

I still think it’s a good compromise considering that Kotlin doesn’t offer much more when it comes to map-building syntax.

```kotlin
"allUsers"("type" to "users", "limit" to 10) {
    select("name")
    select("address") {
        select("city")
        select("street"("postCode" to true)) 
    }
}
```

The to method that allows for that comes from the standard library.

```kotlin
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
```

Note that the `infix` keyword is what allows for the simplified notation `receiver method argument`.

Finally, a slightly more complicated definition of `String.invoke` accepts instances of `Pair<String, T>` allowing for the _`to`_ syntax to be used when specifying field arguments. The explicit String type as the left type helps keeping it all a little more robust.

```kotlin
operator fun <T> String.invoke(vararg args: Pair<String, T>, block: (Field.Builder.() -> Unit)? = null): Field.Builder
```

## Wrapping up

As you can see, I’m not a DSL expert (at all!) but this is a fun experiment to play with. You can follow my work at the [graphql-forger](https://github.com/alediaferia/graphql-forger) repo. Please, feel free to contribute by opening issues or pull requests.

I hope you have enjoyed the post and learnt something new about Kotlin.

The post [Writing a GraphQL DSL in Kotlin](https://alediaferia.com/2019/03/18/writing-graphql-dsl-kotlin/) appeared first on [Ale's main thread](https://alediaferia.com).

{% github alediaferia/graphql-forger %}