GraphQL vs REST in Kotlin: Was man 2025 für das Backend wählen sollte

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: REST ist tot, es lebe GraphQL? (Spoiler: nein)

\n

Wenn Sie in Kotlin programmieren und ein Backend entwickeln, haben Sie sicherlich vom heiligen Krieg gehört: GraphQL vs REST. In einer Ecke des Rings – der gute alte REST, den jeder Junior kennt. In der anderen – das modische GraphQL, das verspricht: „Gib mir das, was ich nicht weiß, aber nur mit einer einzigen Anfrage.“

\n

Ich bin Backend-Entwickler mit Erfahrung in Kotlin und habe in den letzten Jahren drei Projekte von REST auf GraphQL und wieder zurück umgestellt. Spoiler: Jedes Werkzeug ist für seine Aufgabe gut. In diesem Artikel werden wir nicht fanatisch sein. Stattdessen analysieren wir anhand realer Codebeispiele, wann REST in Kotlin gewinnt und wann GraphQL Ihr Retter ist.

\n

Los geht's mit dem Vergleich von GraphQL und REST in Kotlin ohne unnötige Füllwörter und Marketing.

\n\n

1. Kurz und knapp: Was ist was

\n

Bevor wir in den Code eintauchen, lassen Sie uns die Begriffe klären. REST API ist ein Architekturstil, bei dem jede Ressource (Benutzer, Bestellung, Produkt) ihre eigene URL und HTTP-Methoden (GET, POST, PUT, DELETE) hat. Kotlin-Entwickler verwenden meist Spring Boot oder Ktor zur Erstellung von REST-Diensten.

\n

GraphQL ist eine Abfragesprache, bei der Sie einen einzigen Endpunkt haben (normalerweise /graphql), und der Client selbst entscheidet, welche Felder er benötigt. In Kotlin sind die Bibliotheken KGraphQL (leichtgewichtig) und Spring for GraphQL (für Spring-Fans) beliebt.

\n

Der Hauptunterschied: REST bedeutet „Der Server diktiert, was zurückgegeben wird“. GraphQL bedeutet „Der Client fordert nur das an, was er braucht“.

\n\n

2. Beispiel einer REST API in Kotlin (Ktor)

\n

Beginnen wir mit dem Klassiker. Angenommen, wir haben einen Online-Shop. Wir benötigen Daten über einen Benutzer und seine letzten Bestellungen.

\n

So sieht ein typischer REST-Controller in Ktor (einem leichten Framework für Kotlin) aus:

\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 für die Antwort\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

Problem: Wenn der Client (eine mobile App) nur die E-Mail-Adresse des Benutzers benötigt, gibt der Server trotzdem das vollständige Objekt UserResponse mit Bestellungen zurück. Dies ist Over-Fetching – übermäßige Datenübertragung. In schwachen Mobilfunknetzen ist das schmerzhaft.

\n

Lösung Nummer eins: mehrere kleine Endpunkte erstellen: GET /api/users/{id}/email. Aber dann steigt die Anzahl der Anfragen (Under-Fetching).

\n\n

3. Beispiel für GraphQL in Kotlin (Spring for GraphQL)

\n

Jetzt das gleiche Szenario, aber mit GraphQL. Hier ist das 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

Und das ist der Kotlin-Code mit Spring for GraphQL (annotationsbasierter Ansatz):

\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 ohne unnötige Felder\ndata class User(val id: Int, val name: String, val email: String, val lastOrders: List<Order>)
\n\n

Jetzt kann der Client nur das anfordern, was er braucht:

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

Blogs

Buchempfehlungen