Introdução ao GraphQL e Kotlin
GraphQL é uma linguagem de consulta para APIs que permite que os clientes recebam apenas os dados de que realmente precisam. Diferente do REST, onde cada endpoint retorna uma estrutura fixa, o GraphQL oferece flexibilidade: uma única consulta pode combinar dados de diferentes fontes. Kotlin, por sua vez, é uma linguagem moderna para a JVM que combina concisão e segurança de tipos. Neste tutorial, criaremos uma API GraphQL completa usando Kotlin e a biblioteca graphql-kotlin-spring-server.
Você aprenderá como configurar um projeto, definir um esquema, escrever resolvers e testar a API através do GraphiQL. Pronto? Vamos lá!
1. Configuração do Projeto
1.1. Criando uma Aplicação Spring Boot
Primeiro, vamos criar um novo projeto no Spring Initializr. Selecione:
- Projeto: Gradle (Kotlin)
- Linguagem: Kotlin
- Spring Boot: 3.2+
- Dependências: Spring Web, Spring Boot DevTools
Após o download, adicione a dependência GraphQL ao 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. Configuração da Aplicação
Crie um arquivo application.yml em src/main/resources:
server: port: 8080
graphql: packages: - "com.example.graphql.demo"Isso instruirá o Spring Boot a escanear o pacote com.example.graphql.demo em busca de resolvers e tipos.
2. Definindo o Esquema GraphQL
2.1. Criando o Modelo de Dados
Vamos criar um modelo simples para um livro e um autor. Em Kotlin, usamos classes de dados:
// 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. Definindo o Esquema via Código (SDL)
Em vez de escrever um arquivo schema.graphqls, usaremos as anotações @GraphQLDescription e @GraphQLIgnore. A biblioteca graphql-kotlin gera automaticamente o esquema com base nas classes. No entanto, para maior clareza, vamos criar um arquivo schema.graphqls em 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. Implementando Resolvers
3.1. Serviço de Armazenamento de Dados
Para simplificar, usaremos armazenamento em memória:
// 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. Resolver de Consulta
Crie um resolver para consultas:
// 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. Resolver de Mutação
Crie um resolver para mutações:
// 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. Testando a API
4.1. Iniciando a Aplicação
Execute a aplicação através da classe principal ou usando o comando:
./gradlew bootRunApós a inicialização, o endpoint GraphQL estará disponível em http://localhost:8080/graphql, e a interface GraphiQL em http://localhost:8080/graphiql.
4.2. Exemplos de Consultas
Abra o GraphiQL e execute as seguintes consultas:
Obtendo todos os livros:
query { books { id title author { name } year }}Obtendo um livro por ID:
query { book(id: "1") { title author { name } }}Adicionando um novo livro:
mutation { addBook(title: "Admirável Mundo Novo", authorId: "1", year: 1932) { id title author { name } }}Conclusão
Criamos uma API GraphQL totalmente funcional usando Kotlin e Spring Boot. Neste tutorial, cobrimos as etapas básicas: configuração do projeto, definição do esquema, implementação de resolvers e testes. O GraphQL oferece recursos poderosos para recuperação flexível de dados, e o Kotlin torna o código conciso e seguro.
Para estudos adicionais, recomendamos explorar subscriptions, tratamento de erros e integração com bancos de dados. Boa sorte com seu desenvolvimento!