GraphQL 和 Kotlin 简介
GraphQL 是一种 API 查询语言,它允许客户端只获取他们真正需要的数据。与 REST 中每个端点返回固定结构不同,GraphQL 提供了灵活性:一个查询可以合并来自不同来源的数据。而 Kotlin 是一种面向 JVM 的现代语言,它结合了简洁性和类型安全性。在本教程中,我们将使用 Kotlin 和 graphql-kotlin-spring-server 库创建一个完整的 GraphQL API。
您将学习如何配置项目、定义模式、编写解析器以及通过 GraphiQL 测试 API。准备好了吗?开始吧!
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. 应用程序配置
在 src/main/resources 中创建 application.yml 文件:
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.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. 通过代码定义模式 (SDL)
我们不会编写 schema.graphqls 文件,而是使用 @GraphQLDescription 和 @GraphQLIgnore 注解。graphql-kotlin 库会根据类自动生成模式。但是,为了清晰起见,我们在 src/main/resources 中创建一个 schema.graphqls 文件:
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. 数据存储服务
为简单起见,我们将使用内存存储:
// 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 = "乔治·奥威尔"), 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 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("作者未找到") val book = Book(id = UUID.randomUUID().toString(), title = title, author = author, year = year) books.add(book) return book }}