1. Was ist GraphQL

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools."

— graphql.org
  • Query Language: Definiert, was abgefragt wird.

    • Standardisiertes Mittel, um Informationen aus einem System, z. B. einer Datenbank oder einer API, zu holen.

  • API: Die Schnittstelle, die diese Abfragen ermöglicht.

  • Runtime: Führt die Abfragen aus und liefert die Ergebnisse.

1.1. Rest vs. GraphQL

GraphQL und REST verfolgen unterschiedliche Ansätze, wenn es um den Zugriff auf Daten geht.

Während bei REST jede Datenressource über einen eigenen Endpunkt angesprochen werden muss, erlaubt GraphQL dem Client, alle benötigten Informationen in einer einzigen Abfrage zu definieren und gebündelt abzurufen.

  • REST API – Der Client kommuniziert mit mehreren separaten Endpunkten, um Informationen zu erhalten.

  • GraphQL API – Der Client sendet eine einzige Abfrage, die alle gewünschten Daten beinhaltet. Die GraphQL-Schicht übernimmt das Routing zu den jeweiligen Datenquellen im Hintergrund.

1.1.1. REST

Was ist REST?

REST steht für REpresentational State Transfer und ist ein Architekturstil für Web-APIs. Er basiert auf dem HTTP-Protokoll und nutzt dessen Methoden wie GET, POST, PUT und DELETE, um auf Daten zuzugreifen oder diese zu verändern.

In einer REST-API ist jede Ressource (z.B. Menü, Preis oder Image) durch eine eindeutige URL (Endpunkt) identifizierbar. Die Kommunikation erfolgt über mehrere solcher Endpunkte, wobei jede Anfrage eine vordefinierte Antwortstruktur liefert.

Beispiel: Um Informationen über ein Menü und dessen Bilder zu erhalten, muss der Client zwei Requests senden:

  • /menu/123

  • /menu/123/image

Nachteile:

  • Mehrere Requests für zusammenhängende Daten

  • Feste Antwortformate

  • Oft unnötige oder unvollständige Daten (Over-/Underfetching)

Typisch für REST:

  • Feste Routen wie /users, /posts, /comments

  • Eine Antwortstruktur pro Endpunkt

  • Separate HTTP-Requests pro Datenobjekt

// Request
GET https://myrestapi.com/users/1

// Response
{
    "_id": "1",
    "name": "John Doe",
    "username": "johndoe",
    "email": "johndoe@gmail.com",
    "currentJobTitle": "Software Engineer",
    "phone": "9876543210",
    "gender": "MALE",
    "country": "Germany",
    "display_picture": "8ba58af0-1212-4938-8b4a-t3m9c4371952",
    "phone_verified": true,
    "email_verified": true,
    "_created_at": "2024-05-06T13:11:41Z",
    "_updated_at": "2024-05-08T13:11:41Z",
    "_deleted": false
}

1.1.2. GraphQL

GraphQL ist eine alternative API-Technologie, der Client formuliert eine einzige Abfrage, in der genau angegeben wird, welche Felder und Objekte benötigt werden. Diese Anfrage wird an einen zentralen Endpunkt geschickt.

Im Hintergrund sorgt GraphQL dafür, dass alle relevanten Datenquellen kontaktiert und die Ergebnisse in einer einzigen, strukturierten Antwort zusammengeführt werden.

Vorteile:

  • Nur ein Request nötig

  • Flexible, client-gesteuerte Antwortstruktur

  • Keine überflüssigen Daten

Beispiel: Mit einer einzigen Abfrage können Benutzerinformationen und zugehörige Beiträge geladen werden – ohne mehrere HTTP-Aufrufe.

Typisch für GraphQL:

  • Ein einziger Endpunkt (z. B. /graphql)

  • Der Client bestimmt Struktur und Umfang der Antwort

  • Kombinierte Daten aus mehreren Ressourcen in einer einzigen Antwort

// Request
POST https://mygraphqlapi.com/

// Request Body
query getByUserId(userId:$userId){
    name
    email
    currentJobTitle
  }

// Response
{
    "name": "John Doe",
    "email": "johndoe@gmail.com",
    "currentJobTitle": "Software Engineer",
}

1.1.3. GraphQL - Transport

In Beispiel darüber wird GraphQL über HTTP angesprochen. Es ist jedoch nicht auf HTTP beschränkt. Da GraphQL kein Transportprotokoll ist, sondern ein Abfragesystem, kann es auch über andere Protokolle wie WebSocket oder gRPC verwendet werden.

GraphQL definiert, wie man Daten abfragen oder manipulieren kann – nicht, wie diese Daten transportiert werden.

In der Praxis wird GraphQL meist über HTTP verwendet, zB.:

  • POST /graphql – mit einer Query im Body

  • GET /graphql?query={…​} – seltener, für einfache Lese-Requests

Der Vorteil:

  • Bekannte HTTP-Mechanismen

  • Authentifizierung

  • Bestehende Infrastruktur nutzen

Alternative Transportprotokolle: (möglich, aber seltener) GraphQL kann theoretisch auch über andere Protokolle laufen, z.B.:

  • WebSockets – z. B. für Subscriptions (live updates)

  • MQTT / AMQP – in IoT- oder Messaging-Systemen

  • gRPC – in performanteren Umgebungen

graphql with grpc ws http

2. Welches Problem löst GraphQL?

Bei klassischen REST-APIs stößt man in der Praxis schnell auf folgende Herausforderungen:

Problem Beschreibung

Overfetching

Der Client erhält mehr Daten als benötigt, z.B. alle User-Felder, obwohl nur Name und E-Mail angezeigt werden sollen.

Underfetching

Es werden mehrere Requests nötig, um zusammengehörige Daten zu laden, z.B. zuerst ein User, dann separat seine Posts.

Viele Endpunkte

Für komplexe UIs müssen Daten aus verschiedenen Endpunkten zusammengeführt werden – das macht das Frontend komplexer.

Fehlende Flexibilität

  • REST-Endpunkte sind serverdefiniert – das Frontend muss sich anpassen.

  • Mit GraphQL definiert das Frontend, welche Daten es braucht – unabhängig von serverseitigen Endpunkten.

Versionierung

API-Änderungen führen oft zu neuen Versionen (z.B. /v1, /v2), was Wartung erschwert.

Transparenz

  • Bei REST muss man oft Dokus lesen oder Trial & Error machen.

  • GraphQL ist introspektiv: Clients können das Schema abfragen und automatisch Dokumentation und Tooling generieren.

3. Wie funktioniert GraphQL?

Idee: Der Client bestimmt, was er braucht – und der Server liefert genau das.

3.1. Grundprinzipien

Request (oder operation)

Response

{
  hero {
    name
    appearsIn
  }
}
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "appearsIn": [
        "NEWHOPE",
        "EMPIRE",
        "JEDI"
      ]
    },
    .....
  }
}

Der GraphQL-Server dient als mittlere Schicht zwischen Client und dem eigentlichen Backend. Er ist verantwortlich für die Verarbeitung der Anfragen und das Bereitstellen der Daten.

Die wichtigsten Komponenten im Überblick:

  • Schema: Definiert alle verfügbaren Typen, Felder und Operationen (Queries, Mutations, Subscriptions) im System.

  • Query Language: Der Client formuliert seine Datenanfragen mit der deklarativen GraphQL-Abfragesprache.

  • Resolver: Serverseitige Funktionen, die einzelne Felder in einer Abfrage mit konkreten Daten füllen – z. B. aus einer Datenbank, einem Cache oder einer REST-API.

  • Response: Die Antwort des Servers spiegelt genau die Struktur der Anfrage wider – keine überflüssigen Daten, keine Überraschungen.

3.2. Schemas & Types

Ein GraphQL-Schema definiert die gesamte API-Struktur.

  • Welche Datenobjekte verfügbar sind (Object Types)

  • Welche Felder diese besitzen (inkl. Typen und Argumenten)

  • Welche Operationen erlaubt sind (Queries, Mutations, Subscriptions)

Beispiel für einen Typ in SDL (Schema Definition Language):

type User {
    name: String
    email: String
    posts: [Post]
}


type Post {
    title: String
    description: String
    user: User
}

GraphQL definiert verschiedene Typen, die wir zum Aufbau eines Schemas verwenden können:

  • Scalar Type

  • Object Type

  • Input Types

  • Enumeration Type

  • Union and Interface Type

  • Lists and Non-Null

Details
# normal scalars are Int, Float, String, Boolean, ID (serialized as a String)
# Custom scalar, to use Date it has to be implemented in the GraphQL-Server
scalar Date


# Enum type
enum Role {
  ADMIN
  USER
  GUEST
}

# Interface type
interface MediaItem {
  id: ID!
  title: String!
}

# Object types
type Book implements MediaItem {
  id: ID!
  title: String!
  author: Author!
  published: Date
}

type Movie implements MediaItem {
  id: ID!
  title: String!
  director: String!
  released: Date
}

type Author {
  id: ID!
  name: String!
  books: [Book!]!
}

type User {
  id: ID!
  name: String!
  email: String!
  role: Role!
}

# Union type
union SearchResult = Book | Author | Movie

# Input types
input CreateBookInput {
  title: String!
  authorId: ID!
  published: Date
}

input CreateUserInput {
  name: String!
  email: String!
  role: Role = USER
}

# Query type also root type
type Query {
  books: [Book!]!
  users: [User!]!
  authors: [Author!]!
  search(keyword: String!): [SearchResult!]!
  me: User
}

# Mutation type also root type
type Mutation {
  createBook(input: CreateBookInput!): Book!
  createUser(input: CreateUserInput!): User!
  assignRole(userId: ID!, role: Role!): User!
}

# Subscription type also root type
type Subscription {
  bookAdded: Book!
  userSignedUp: User!
}

3.2.1. Query

  • Query ist einer der drei speziellen Einstiegspunkte (Root-Typen) in einem GraphQL-Schema.

  • Er wird verwendet, um Daten vom Server zu lesen.

  • Jede Query startet beim Query-Typ, der als Ausgangspunkt für Abfragen dient.

  • Clients definieren in der Abfrage exakt, welche Felder (und verschachtelten Felder) sie benötigen.

  • Beispiel:

    query {
      books {
        title
        author {
          name
        }
      }
    }

3.2.2. Mutation

  • Mutation ist ein weiterer Root-Typ im Schema und wird verwendet, um Daten zu verändern.

  • Dazu gehören Operationen wie Erstellen, Aktualisieren oder Löschen von Objekten.

  • Mutationen ähneln vom Aufbau her Queries, haben jedoch Nebeneffekte (z. B. Datenbankeinträge).

  • Mutationen im GraphQL-Schema beginnen beim Mutation-Typ.

  • Beispiel:

    mutation {
      createBook(
            input: { title: "Neu", authorId: "1" } # input, definiert im schema
        ) { # return felder
        id
        title
      }
    }

3.2.3. Subscription

  • Subscription ist der dritte Root-Typ und dient der Echtzeitkommunikation.

  • Damit können Clients eine dauerhafte Verbindung zum Server (z. B. über WebSockets) aufbauen.

  • Der Server sendet Live-Updates an alle verbundenen Clients, wenn bestimmte Ereignisse eintreten (z. B. ein neues Objekt wird erstellt).

  • Abfragen starten beim Subscription-Typ.

  • Beispiel:

    subscription {
      bookAdded {
        id
        title
      }
    }

3.3. Resolver

Resolver sind Funktionen im Server-Code, die bestimmen, wie und woher die Daten in einer GraphQL-Abfrage tatsächlich geholt oder verändert werden. Während das Schema definiert, was möglich ist, liefern Resolver die Logik, um das umzusetzen.

  • Jeder Feldname im GraphQL-Schema benötigt eine zugehörige Resolver-Funktion, außer er kann automatisch auf ein gleichnamiges Feld im Datenobjekt gemappt werden.

  • Resolver erhalten die Argumente aus der Query oder Mutation und haben Zugriff auf den Kontext (z. B. Authentifizierungsinformationen).

  • Besonders bei Mutationen (z. B. createBook, deleteBook) implementieren Resolver die tatsächlichen Schreiboperationen (z. B. Datenbankzugriffe).

  • Bei Abfragen (Queries) holen Resolver die angeforderten Daten aus Datenquellen wie Datenbanken, APIs oder internen Diensten.

Beispiel für einen Resolver in JavaScript (z. B. mit Apollo Server):

type Book {
  id: ID!
  title: String!
  author: Author!
}

type Author {
  id: ID!
  name: String!
}

type Query {
  books: [Book!]!
}

type Mutation {
  deleteBook(id: ID!): Book
}
const books = [
  { id: '1', title: 'GraphQL Basics', authorId: 'a1' },
  { id: '2', title: 'Advanced GraphQL', authorId: 'a2' },
];

const authors = [
  { id: 'a1', name: 'Alice' },
  { id: 'a2', name: 'Bob' },
];

const resolvers = {
  Query: {
    books: () => books,
  },
  Mutation: {
    deleteBook: (_, { id }) => {
      const index = books.findIndex(book => book.id === id);
      if (index === -1) return null;
      const [deleted] = books.splice(index, 1);
      return deleted;
    },
  },
  Book: { //resolve the author because book array only holds author.id
    author: (book) => authors.find(author => author.id === book.authorId),
  },
};

Beispiel für Verwendung:

mutation {
  deleteBook(id: "1") {
    id
    title
  }
}

Erwartete Antwort:

{
  "data": {
    "deleteBook": {
      "id": "1",
      "title": "GraphQL Basics"
    }
  }
}

Mit Resolvern wird also die eigentliche Geschäftslogik angebunden – sie sind das Bindeglied zwischen dem deklarativen Schema und der realen Datenquelle (z. B. Datenbank, API).

3.4. Implementationen

GraphQL kann mit verschiedenen Programmiersprachen und Frameworks implementiert werden. Die konkrete Ausführung – also wie Abfragen verarbeitet, Resolver ausgeführt und Datenquellen angebunden werden – übernimmt jeweils eine Library oder ein Framework. Je nach Sprache unterscheiden sich Aufbau und Syntax, das Grundprinzip bleibt jedoch identisch.

3.4.1. Beliebte Implementationen (Auswahl)

  • Apollo Server (JavaScript/Node.js)

    • Weit verbreitet, besonders für Web- und Fullstack-Entwicklung.

    • Unterstützt einfache Resolverstruktur, Middleware (z. B. Authentifizierung) und Subscriptions.

  • GraphQL Java

    • Robuste Low-Level-Implementierung für Java.

    • Wird oft in Spring Boot-Projekten verwendet.

  • SmallRye GraphQL (MicroProfile / Jakarta EE)

    • Integration in das MicroProfile-Ökosystem (Quarkus, Payara, WildFly etc.).

    • Nutzt Annotationen zur Definition von Schema und Resolvern.

  • HotChocolate (.NET)

    • Moderne und flexible GraphQL-Bibliothek für .NET Core.

  • graphql-go (Go)

    • Leichtgewichtige, native Implementierung für Go-Projekte.

3.4.2. Fokus: SmallRye GraphQL

SmallRye GraphQL ist eine Spezialisierung für Java-Anwendungen im MicroProfile-Umfeld. Es basiert auf GraphQL Java und erlaubt es, ein Schema per Annotationen direkt auf Java-Klassen zu definieren.

Beispiel für eine einfache Abfrage:

@GraphQLApi
public class BookService {

    // Resolver für: query { books { title author } }
    @Query
    public List<Book> books() {
        return bookRepository.findAll();
    }

    // Resolver für: mutation { addBook(title: "...", author: "...") { title } }
    @Mutation
    public Book addBook(String title, String author) {
        Book book = new Book(title, author);
        return bookRepository.save(book);
    }
}

Die zugehörige Java-Klasse:

public class Book {
    public String title;
    public String author;

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }
}

Besonderheiten von SmallRye GraphQL:

  • Annotationen wie @Query, @Mutation, @Subscription machen separate SDL-Dateien überflüssig.

  • Integrierbar in Java-Frameworks wie Quarkus, Payara, WildFly.

  • Automatische Schema-Generierung aus Java-Klassen.

  • Integration in REST-APIs über CDI (Context and Dependency Injection) und JAX-RS möglich.

  • GraphQL UI (Explorer) oft standardmäßig verfügbar unter /graphql-ui.

Resolver-Funktionen in SmallRye GraphQL werden automatisch aus annotierten Methoden erzeugt. Du brauchst keine separate Resolver-Map oder Schema-Dateien. Die Magie passiert durch Annotationen und Reflektion im Hintergrund.

In z.B. Apollo müssen die resolver selbst geschrieben werden. (siehe 3.3)

4. Entwicklung von GraphQL

Über die Jahre sind viele API-Standards entstanden, die alle ihre Vor- und Nachteile haben. GraphQL ist ein relativ neuer Standard, der 2012 von Facebook entwickelt wurde und 2015 als Open Source veröffentlicht wurde.

4.2. Wieso entstand GraphQL?

GraphQL wurde 2012 bei Facebook entwickelt, um die Herausforderungen beim Datenabruf in mobilen Apps zu lösen. Insbesondere bei der Umstellung von Web-Wrappern hin zu nativen mobilen Anwendungen stieß Facebook an Grenzen mit bestehenden API-Ansätzen wie REST.

Facebook apps waren ursprünglich Web-Wrapper ("write once, run anywhere"), die auf mobile Geräte portiert wurden. Was bei der steigenden komplexität zu schlechter Performance und Nutzererfahrung führte.

4.2.1. Probleme mit klassischen APIs

  • REST führte zu Overfetching/Underfetching und vielen Round-Trips.

  • HTML-basierte Inhalte (z.B. der News Feed) waren schwer für mobile Apps nutzbar.

  • Entwickler wollten APIs näher an der Modellstruktur der App.

  • Komplexe Datenstrukturen erforderten aufwändige Server- und Client-Logik.

4.2.2. Die Lösung: GraphQL

GraphQL wurde als neue Datenabfragesprache entwickelt, die sich an den Bedürfnissen von Produktdesignern und Entwicklern orientiert. Die wichtigsten Eigenschaften:

  • Client-zentriert: Die App bestimmt die Struktur der Daten durch eine Abfrage.

  • Hierarchisch: Abfragen spiegeln die Objektbeziehungen wider – passend zur UI.

  • Unabhängig vom Speicher: GraphQL ist ein Protokoll, kein Datenbanksystem. (jedes Feld kann aus beliebigen Datenquellen stammen)

  • Introspektiv: Clients können das API-Schema selbst abfragen.

  • Versionsfrei: Neue Felder können hinzugefügt werden, ohne alte Clients zu brechen.

4.2.3. Erfolge bei Facebook

  • 2012: News Feed wurde mit GraphQL nativ auf iOS und Android umgesetzt.

  • Heute: Milliarden von Anfragen täglich für hunderte App-Versionen.

  • Entwicklertools wie GraphQL und Frameworks wie Relay wurden darauf aufgebaut.

  • Eine (Js)Referenz-Implementierung und die Spezifikation wurden open-sourced, um eine Community aufzubauen.

Spezifikation: GraphQL Specification

5. Wer benutzt GraphQL?

5.1. GitHub

Was GitHub mit GraphQL macht:

Seit 2016 bietet GitHub eine offizielle GraphQL API v4 an.

  • Sie wurde entwickelt, um komplexe und flexible Datenabfragen zu ermöglichen.

  • Viele interne Tools und neuere Features (z. B. GitHub Projects, Actions, Insights) nutzen intern GraphQL.

  • Entwickler können mit einer einzigen Abfrage z. B. Repositories, Issues, Pull Requests und Commits abfragen – was mit REST mehrere Aufrufe bräuchte.

Aber: Die REST API (v3) bleibt bestehen.
  • GitHub betreibt beide APIs parallel, um Abwärtskompatibilität zu wahren.

  • Für einfache Anwendungsfälle oder Skripte ist REST oft schneller umzusetzen.

GitHub hat GraphQL eingeführt, um REST zu ergänzen, nicht zu ersetzen. Die GraphQL API ist die empfohlene Wahl für neue, komplexe Anwendungen, während REST weiterhin für einfache oder etablierte Workflows genutzt werden kann.

Example
get all repositories with some details
query {
  viewer {
    repositories(first: 100, orderBy: {field: NAME, direction: ASC}) {
      nodes {
        name
        description
        url
        isPrivate
      }
    }
  }
}
recent pull requests
query {
  viewer {
    pullRequests(first: 10, orderBy: {field: CREATED_AT, direction: DESC}) {
      nodes {
        title
        url
        createdAt
        state
        repository {
          nameWithOwner
        }
      }
    }
  }
}
introspection (Selbstbeobachtung)
query {
  __schema {
    types {
      name
    }
  }
}

6. Beispiel Projekt

In diesem Beispielprojekt wird eine einfache GraphQL-API für Autos und Motoren implementiert. Die Anwendung basiert auf Quarkus, verwendet Hibernate ORM für die Datenbankanbindung und SmallRye GraphQL zur Bereitstellung der GraphQL-Schnittstelle.

6.1. Datenmodell

Das Datenmodell besteht aus den Entitäten Car, Engine und einem Enum FuelType, welches den Motortyp beschreibt (z. B. PETROL, DIESEL, ELECTRIC etc.).

uml

6.2. Struktur

src/main/java/
└── at/
    └── htl/
        ├── boundary/
        │   └── CarGraphQLResource.java
        ├── controller/
        │   ├── CarRepository.java
        │   └── EngineRepository.java
        └── entity/
            ├── Car.java
            ├── FuelType.java
            └── Engine.java

6.3. Entitäten

Die Entitäten Car, Engine und FuelType sind wie bei einer Standard JPA-Anwendung definiert. Sie sind mit @Entity annotiert und repräsentieren die Datenbanktabellen.

Es werden keine zusätzlichen Annotationen für SmallRye GraphQL benötigt um das GraphQL schema zu generieren. Passiert onehin automatisch.
Entitäten
Car.java
@Entity
public class Car {
    public String brand;
    public String model;
    public int manufactureYear;
    public String color;
    public String vin;
    @ManyToOne
    @JoinColumn(name = "engine_id")
    private Engine engine;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    ... //Getter Setter
}
Engine.java
@Entity
public class Engine{

    public int power; // in HP

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private FuelType fuelType;

    public int cylinders;

    public double displacement;
    public boolean turbocharged;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;    ... //Getter Setter
FuelType.java
package at.htl.entity;

public enum FuelType {
    PETROL,
    DIESEL,
    ELECTRIC,
    HYBRID,
    LPG,
    HYDROGEN
}

6.4. Repositories

Standard-Implementierung mit PanacheRepository.

Repositories
CarRepository.java
package at.htl.controller;

import at.htl.entity.Car;
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class CarRepository implements PanacheRepository<Car> {
}
EngineRepository.java
package at.htl.controller;

import at.htl.entity.Engine;
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class EngineRepository implements PanacheRepository<Engine> {
}

6.5. GraphQL-Resource

Die GraphQL-Resource stellt die Schnittstelle nach außen dar. Die Klasse ist mit @GraphQLApi annotiert, wodurch ihre Methoden als GraphQL-Operationen verfügbar gemacht werden. Sie bietet Queries und Mutationen zum Lesen, Hinzufügen, Aktualisieren und Löschen von Autos.

@GraphQLApi (1)
@ApplicationScoped
public class CarGraphQLResource {

    @Inject
    CarRepository carRepository;

    @Inject
    EngineRepository engineRepository;

    @Query("cars") (4)
    public List<Car> getCars() {
        return carRepository.listAll();
    }

    @Mutation (2)
    @Transactional (3)
    public Car addCar(
            @Name("brand") String brand,     (4)
            @Name("model") String model,
            @Name("year") int year,
            @Name("color") String color,
            @Name("vin") String vin,
            @Name("engine") Engine engine
    ) {
        // Add and return car
    }

    @Mutation (5)
    @Transactional (3)
    public Car updateCar(
            @Name("id") Long id,             (4)
            @Name("brand") String brand,
            @Name("model") String model,
            @Name("year") int year,
            @Name("color") String color,
            @Name("vin") String vin
    ) {
       // Update and return car
    }

    @Mutation (5)
    @Transactional (3)
    public boolean deleteCar(@Name("id") Long id) { (4)
        //Delete car and return true/false
    }
}
1 @GraphQLApi: Markiert die Klasse als GraphQL-Endpunkt. Alle öffentlichen Methoden können damit als GraphQL-Operationen verwendet werden.
2 @Query: Kennzeichnet eine Methode als GraphQL-Query (Lesefunktion).
3 @Transactional: Stellt sicher, dass Datenbankoperationen innerhalb einer Transaktion ausgeführt werden.
4 @Name(…​): Gibt den Namen des Arguments in der GraphQL-API explizit an.
5 @Mutation: Markiert eine Methode als Mutation – also Schreiboperation wie Hinzufügen, Aktualisieren oder Löschen.

6.6. Ergebnis

Querys & Mutationen
cars
query {
  cars {
    id
    brand
    model
    manufactureYear
    color
    vin
    engine {
      id
      power
      fuelType
      cylinders
      displacement
      turbocharged
    }
  }
}
addcar
mutation {
  addCar(
    brand: "Renault"
    model: "Laguna"
    manufactureYear: 2011
    color: "Dark Blue"
    vin: "VF1KG0E0641234567"
    engine: {
      power: 130
      fuelType: DIESEL
      cylinders: 4
      displacement: 1.9
      turbocharged: false
    }
  ) {
    id
    brand
    model
    manufactureYear
  }
}
update
mutation {
  updateCar(
    id: 10
    brand: "Renault"
    model: "Laguna GT"
    manufactureYear: 2012
    color: "Midnight Blue"
    vin: "VF1KG0E0649999999"
  ) {
    id
    brand
    model
    manufactureYear
    color
    vin
  }
}
delete
mutation {
  deleteCar(id: 10)
}

7. Fazit zu GraphQL

7.1. Ist GraphQL ein Ersatz für REST?

  • Kann REST in vielen Bereichen ergänzen oder ersetzen, ist aber kein vollständiger Ersatz

  • Besonders geeignet für komplexe, flexible Datenabfragen (z.B. Github)

  • REST bleibt sinnvoll bei einfachen Szenarien

7.2. Benutzerfreundlichkeit

  • Einfache Nutzung für Clients nach kurzer Einarbeitung

  • Klar strukturierte, flexible Queries erleichtern Entwicklung

  • Serverseitig erfordert es eine gute Planung und Schema-Design

7.3. Performance

  • Vorteile durch gezielte Abfragen und weniger Datentransfer

  • Kann bei schlechtem Schema-Design (z.B. N+1-Probleme) zu Performanceproblemen führen. N+1-Problem:

    • Server fragt alle Bücher ab: SELECT * FROM books → z.B. 100 Bücher

    • 100x SELECT * FROM authors WHERE id = …​ → eine Anfrage pro Buch, um den Autor zu holen

  • Lösungen wie DataLoader können Performance deutlich verbessern

7.4. Was kann GraphQL nicht?

  • Kein standardmäßiges Caching vorhanden

  • Keine integrierte Lösung für Datei-Uploads

  • Keine integrierte Echtzeitkommunikation (z.B. WebSockets notwendig)

  • Komplexe Abfragen können Serverressourcen stark beanspruchen und erfordern passende Skalierungsstrategien