GraphQL API с Kotlin: пошаговый туториал

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в GraphQL и Kotlin

GraphQL — это язык запросов для API, который позволяет клиентам получать только те данные, которые им действительно нужны. В отличие от REST, где каждый эндпоинт возвращает фиксированную структуру, GraphQL дает гибкость: один запрос может объединять данные из разных источников. Kotlin, в свою очередь, — современный язык для JVM, который сочетает лаконичность и безопасность типов. В этом туториале мы создадим полноценный GraphQL API с помощью Kotlin и библиотеки graphql-kotlin-spring-server.

Вы узнаете, как настроить проект, определить схему, написать резолверы и протестировать API через GraphiQL. Готовы? Поехали!

1. Настройка проекта

1.1. Создание Spring Boot приложения

Для начала создадим новый проект на Spring Initializr. Выберите:

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

После скачивания добавьте в build.gradle.kts зависимость для GraphQL:

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.yml в src/main/resources:

server:
  port: 8080

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

Это укажет Spring Boot сканировать пакет com.example.graphql.demo для поиска резолверов и типов.

2. Определение схемы GraphQL

2.1. Создание модели данных

Создадим простую модель для книги и автора. В Kotlin используем data class:

// src/main/kotlin/com/example/graphql/demo/model/Book.kt
package 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. Определение схемы через код (SDL)

Вместо написания файла schema.graphqls мы воспользуемся аннотациями @GraphQLDescription и @GraphQLIgnore. Библиотека graphql-kotlin автоматически генерирует схему на основе классов. Однако для ясности создадим файл schema.graphqls в 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. Реализация резолверов

3.1. Сервис для хранения данных

Для простоты будем использовать in-memory хранилище:

// src/main/kotlin/com/example/graphql/demo/service/LibraryService.kt
package com.example.graphql.demo.service

import com.example.graphql.demo.model.Author
import com.example.graphql.demo.model.Book
import org.springframework.stereotype.Service
import java.util.UUID

@Service
class LibraryService {
    private val authors = mutableListOf(
        Author(id = "1", name = "Джордж Оруэлл"),
        Author(id = "2", name = "Рэй Брэдбери")
    )

    private val books = mutableListOf(
        Book(id = "1", title = "1984", author = authors[0], year = 1949),
        Book(id = "2", title = "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 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 резолверы

Создадим класс для обработки запросов:

// src/main/kotlin/com/example/graphql/demo/resolver/QueryResolver.kt
package com.example.graphql.demo.resolver

import com.example.graphql.demo.model.Author
import com.example.graphql.demo.model.Book
import com.example.graphql.demo.service.LibraryService
import com.expediagroup.graphql.server.operations.Query
import org.springframework.stereotype.Component

@Component
class QueryResolver(private val service: LibraryService) : Query {
    fun books(): List<Book> = service.getBooks()
    fun book(id: String): Book? = service.getBook(id)
    fun authors(): List<Author> = service.getAuthors()
}

3.3. Mutation резолверы

Теперь добавим мутацию для добавления книги:

// src/main/kotlin/com/example/graphql/demo/resolver/MutationResolver.kt
package com.example.graphql.demo.resolver

import com.example.graphql.demo.model.Book
import com.example.graphql.demo.service.LibraryService
import com.expediagroup.graphql.server.operations.Mutation
import org.springframework.stereotype.Component

@Component
class MutationResolver(private val service: LibraryService) : Mutation {
    fun addBook(title: String, authorId: String, year: Int): Book {
        return service.addBook(title, authorId, year)
    }
}

4. Запуск и тестирование

4.1. Запуск приложения

Добавьте главный класс приложения:

// src/main/kotlin/com/example/graphql/demo/GraphqlDemoApplication.kt
package com.example.graphql.demo

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class GraphqlDemoApplication

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

Запустите приложение через Gradle: ./gradlew bootRun.

4.2. Тестирование через GraphiQL

Откройте браузер и перейдите на http://

Блоги

Рекомендаций по книгам