GraphQL backend service with Kotlin and Spring Boot

In this blog I will show how to create a very basic GraphQL backend service using Kotlin, Spring and the graphql-kotlin library.

This example is based on the following documentation: https://expediagroup.github.io/graphql-kotlin/docs/spring-server/spring-overview

Step 1: Create a new Spring Initializr project in Intellij.
In the wizard, select Kotlin as language, and add the “Spring Reactive Web” dependency.

Step 2: Add the graphql-kotlin library
Add the following dependency to you pom.xml:

<dependency>
<groupId>com.expediagroup</groupId>
<artifactId>graphql-kotlin-spring-server</artifactId>
<version>3.2.0</version>
</dependency>

Step 2: Rename the application.properties to application.yml
During this witing, the graphql-kotlin throws error when the property file is not in yml format.
The application.yml needs to contain the following:

graphql:
  packages:
      - "com.example.demo"

(Change com.example.demo to your own package)

Step 3: Modify the Demoapplication.kt to the following:

package com.example.demo

import com.expediagroup.graphql.spring.operations.Query
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.stereotype.Component

@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}

val order1 = Order(1, "shirt", 14.50)
val order2 = Order(2, "jeans", 50.00)
val order3 = Order(4, "socks", 3.00)
val order4 = Order(4, "jack", 80.00)
val customer1 = Customer(1, "John", listOf(order1, order2))
val customer2 = Customer(2, "Jack", listOf(order3, order4))
val customers = listOf(customer1, customer2)

@Component
class CustomerQuery : Query {
    fun getCustomers(id:Int): Customer {
        return customers.filter { it.id == id }.first()
    }
    fun allCustomers(): List<Customer> {
        return customers
    }
}

data class Customer(
        val id: Int,
        val name: String,
        val orders: List<Order>)

data class Order(
        val id: Int,
        val item: String,
        val price: Double
)

Step 4: Test the application

We now have a running GraphQL application running!

Spring has created 4 endpoint for us:

http://localhost:8080/sdl : this shows the generated SDL for us (based on the CustomerQuery class)
http://localhost:8080/playground : this shows the Prisma Labs GraphQL Playground IDE endpoint
http://localhost:8080/subscriptions : this endpoint can be used for subscriptions (not used in this example)
http://localhost:8080/grapql : this is the endpoint for processing queries and mutations.

The generated SDL looks that is available under http://localhost:8080/sdl looks like this:

schema {
  query: Query
}

"Directs the executor to include this field or fragment only when the `if` argument is true"
directive @include(
    "Included when true."
    if: Boolean!
  ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

"Directs the executor to skip this field or fragment when the `if`'argument is true."
directive @skip(
    "Skipped when true."
    if: Boolean!
  ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

"Marks the field or enum value as deprecated"
directive @deprecated(
    "The reason for the deprecation"
    reason: String = "No longer supported"
  ) on FIELD_DEFINITION | ENUM_VALUE

"Exposes a URL that specifies the behaviour of this scalar."
directive @specifiedBy(
    "The URL that specifies the behaviour of this scalar."
    url: String!
  ) on SCALAR

type Customer {
  id: Int!
  name: String!
  orders: [Order!]!
}

type Order {
  id: Int!
  item: String!
  price: Float!
}

type Query {
  allCustomers: [Customer!]!
  getCustomers(id: Int!): Customer!
}

The playground can be used to create and test queries.

The graphql endpoint can also be tested with curl:

curl \
-X POST \
-H "Content-Type: application/json" \
--data '{ "query": "{ allCustomers{ id, name }}" }' \
http://localhost:8080/graphql