GraphQL API with Kotlin: Step-by-Step Tutorial

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction to GraphQL and Kotlin

GraphQL is a query language for APIs that allows clients to receive only the data they actually need. Unlike REST, where each endpoint returns a fixed structure, GraphQL provides flexibility: a single query can combine data from different sources. Kotlin, in turn, is a modern language for the JVM that combines conciseness and type safety. In this tutorial, we will create a full-featured GraphQL API using Kotlin and the graphql-kotlin-spring-server library.

You will learn how to set up a project, define a schema, write resolvers, and test the API through GraphiQL. Ready? Let's go!



1. Project Setup

1.1. Creating a Spring Boot Application

First, let's create a new project on Spring Initializr. Select:

  • Project: Gradle (Kotlin)
  • Language: Kotlin
  • Spring Boot: 3.2+
  • Dependencies: Spring Web, Spring Boot DevTools

After downloading, add the GraphQL dependency to build.gradle.kts:

dependencies {    implementation("com.expediagroup:graphql-kotlin-spring-server:7.0.0")    implementation("org.springframework.boot:spring-boot-starter-web")    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")    testImplementation("org.springframework.boot:spring-boot-starter-test")}


1.2. Application Configuration

Create a file application.yml in src/main/resources:

server:  port: 8080

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

This will instruct Spring Boot to scan the com.example.graphql.demo package for resolvers and types.



2. Defining the GraphQL Schema

2.1. Creating the Data Model

Let's create a simple model for a book and an author. In Kotlin, we use data classes:

// src/main/kotlin/com/example/graphql/demo/model/Book.ktpackage com.example.graphql.demo.model

data class Book( val id: String, val title: String, val author: Author, val year: Int)

data class Author( val id: String, val name: String, val books: List<Book> = emptyList())


2.2. Defining the Schema via Code (SDL)

Instead of writing a schema.graphqls file, we will use the @GraphQLDescription and @GraphQLIgnore annotations. The graphql-kotlin library automatically generates the schema based on classes. However, for clarity, let's create a schema.graphqls file in src/main/resources:

type Query {    books: [Book!]!    book(id: String!): Book    authors: [Author!]!}

type Mutation { addBook(title: String!, authorId: String!, year: Int!): Book!}

type Book { id: String! title: String! author: Author! year: Int!}

type Author { id: String! name: String! books: [Book!]!}


3. Implementing Resolvers

3.1. Data Storage Service

For simplicity, we will use in-memory storage:

// src/main/kotlin/com/example/graphql/demo/service/LibraryService.ktpackage com.example.graphql.demo.service

import com.example.graphql.demo.model.Authorimport com.example.graphql.demo.model.Bookimport org.springframework.stereotype.Serviceimport java.util.UUID

@Serviceclass LibraryService { private val authors = mutableListOf( Author(id = "1", name = "George Orwell"), Author(id = "2", name = "Ray Bradbury") )

private val books = mutableListOf( Book(id = "1", title = "1984", author = authors[0], year = 1949), Book(id = "2", title = "Fahrenheit 451", author = authors[1], year = 1953) )

fun getBooks(): List<Book> = books fun getBook(id: String): Book? = books.find { it.id == id } fun getAuthors(): List<Author> = authors fun getAuthor(id: String): Author? = authors.find { it.id == id }

fun addBook(title: String, authorId: String, year: Int): Book { val author = authors.find { it.id == authorId } ?: throw IllegalArgumentException("Author not found") val book = Book(id = UUID.randomUUID().toString(), title = title, author = author, year = year) books.add(book) return book }}


3.2. Query Resolver

Create a resolver for queries:

// src/main/kotlin/com/example/graphql/demo/resolver/QueryResolver.ktpackage com.example.graphql.demo.resolver

import com.example.graphql.demo.model.Authorimport com.example.graphql.demo.model.Bookimport com.example.graphql.demo.service.LibraryServiceimport org.springframework.stereotype.Component

@Componentclass QueryResolver(private val libraryService: LibraryService) {

fun books(): List<Book> = libraryService.getBooks()

fun book(id: String): Book? = libraryService.getBook(id)

fun authors(): List<Author> = libraryService.getAuthors()}


3.3. Mutation Resolver

Create a resolver for mutations:

// src/main/kotlin/com/example/graphql/demo/resolver/MutationResolver.ktpackage com.example.graphql.demo.resolver

import com.example.graphql.demo.model.Bookimport com.example.graphql.demo.service.LibraryServiceimport org.springframework.stereotype.Component

@Componentclass MutationResolver(private val libraryService: LibraryService) {

fun addBook(title: String, authorId: String, year: Int): Book { return libraryService.addBook(title, authorId, year) }}


4. Testing the API

4.1. Launching the Application

Run the application via the main class or using the command:

./gradlew bootRun

After starting, the GraphQL endpoint will be available at http://localhost:8080/graphql, and the GraphiQL interface at http://localhost:8080/graphiql.



4.2. Example Queries

Open GraphiQL and execute the following queries:

Getting all books:

query {    books {        id        title        author {            name        }        year    }}

Getting a book by ID:

query {    book(id: "1") {        title        author {            name        }    }}

Adding a new book:

mutation {    addBook(title: "Brave New World", authorId: "1", year: 1932) {        id        title        author {            name        }    }}


Conclusion

We have created a fully functional GraphQL API using Kotlin and Spring Boot. In this tutorial, we covered the basic steps: setting up the project, defining the schema, implementing resolvers, and testing. GraphQL provides powerful capabilities for flexible data retrieval, and Kotlin makes the code concise and safe.

For further study, we recommend exploring subscriptions, error handling, and integration with databases. Good luck with your development!

Blogs

Book Recommendations