GraphQL vs REST em Kotlin: o que escolher para o backend em 2025

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: REST morreu, viva o GraphQL? (Spoiler: não)

\n

Se você programa em Kotlin e desenvolve backend, certamente já ouviu falar da guerra santa: GraphQL vs REST. Em um canto do ringue — o bom e velho REST, que todo júnior conhece. No outro — o moderno GraphQL, que promete "me dê o que eu quero, mas não sei o quê, em uma única consulta".

\n

Eu sou um desenvolvedor backend com experiência em Kotlin e, nos últimos anos, reescrevi três projetos de REST para GraphQL e vice-versa. Spoiler: cada ferramenta é boa para sua tarefa. Neste artigo, não vamos ser fanáticos. Em vez disso, vamos analisar com exemplos reais de código quando REST em Kotlin vence e quando GraphQL é o seu salvador.

\n

Vamos conferir a comparação entre GraphQL e REST em Kotlin sem enrolação e marketing.

\n\n

1. Resumindo: o que é o quê

\n

Antes de mergulhar no código, vamos alinhar os termos. REST API é um estilo arquitetural onde cada recurso (usuário, pedido, produto) tem sua própria URL e métodos HTTP (GET, POST, PUT, DELETE). Desenvolvedores Kotlin geralmente usam Spring Boot ou Ktor para criar serviços REST.

\n

GraphQL é uma linguagem de consulta onde você tem um único endpoint (geralmente /graphql), e o cliente decide quais campos precisa. Em Kotlin, as bibliotecas populares são KGraphQL (leve) e Spring for GraphQL (para fãs do Spring).

\n

A principal diferença: REST é "o servidor dita o que retornar". GraphQL é "o cliente pede apenas o que precisa".

\n\n

2. Exemplo de REST API em Kotlin (Ktor)

\n

Vamos começar com o clássico. Suponha que temos uma loja online. Precisamos obter dados de um usuário e seus últimos pedidos.

\n

Veja como é um controlador REST típico em Ktor (framework leve para Kotlin):

\n\n
// REST endpoint: GET /api/users/{id}\nfun Application.userModule() {\n    routing {\n        get("/api/users/{id}") {\n            val userId = call.parameters["id"]?.toIntOrNull() ?: return@get call.respondText("Bad Request", status = HttpStatusCode.BadRequest)\n            val user = userService.getUserById(userId) ?: return@get call.respondText("Not Found", status = HttpStatusCode.NotFound)\n            call.respond(user)\n        }\n    }\n}\n\n// Data class para resposta\n@Serializable\ndata class UserResponse(\n    val id: Int,\n    val name: String,\n    val email: String,\n    val lastOrders: List<Order>\n)
\n\n

Problema: se o cliente (aplicativo móvel) precisa apenas do email do usuário, o servidor ainda retorna o objeto completo UserResponse com os pedidos. Isso é over-fetching — transferência excessiva de dados. Em redes móveis lentas, isso é doloroso.

\n

Solução número um: criar vários endpoints menores: GET /api/users/{id}/email. Mas isso aumenta o número de requisições (under-fetching).

\n\n

3. Exemplo de GraphQL em Kotlin (Spring for GraphQL)

\n

Agora o mesmo cenário, mas com GraphQL. Veja o schema (schema.graphqls):

\n\n
type Query {\n    user(id: ID!): User\n}\n\ntype User {\n    id: ID!\n    name: String\n    email: String\n    lastOrders: [Order]\n}\n\ntype Order {\n    id: ID!\n    total: Float\n    date: String\n}
\n\n

E este é o código Kotlin usando Spring for GraphQL (abordagem com anotações):

\n\n
@Controller\nclass UserController(private val userService: UserService) {\n\n    @QueryMapping\n    fun user(@Argument id: Int): User {\n        return userService.getUserById(id) ?: throw UserNotFoundException("User not found")\n    }\n}\n\n// Data class sem campos extras\ndata class User(val id: Int, val name: String, val email: String, val lastOrders: List<Order>)
\n\n

Agora o cliente pode solicitar apenas o que precisa:

\n\n
query {\n    user(id: 42) {\n        email\n    }\n}

Blogs

Book Recommendations