48 Versionierung von REST APIs

API-Versionierung ist ein wichtiger Aspekt bei der Entwicklung von RESTful Webservices, insbesondere wenn sich die API im Laufe der Zeit weiterentwickelt. Durch die Versionierung können Sie Änderungen an der API vornehmen, ohne bestehende Clients zu beeinträchtigen, die ältere Versionen der API verwenden. Dies ermöglicht es, neue Funktionen einzuführen oder Breaking Changes durchzuführen, während ältere Versionen weiterhin unterstützt werden.

In diesem Kapitel zeigen wir, wie Sie API-Versionierung in Spring Boot implementieren können, welche Ansätze es gibt, und wie Sie diese effizient nutzen können.

48.1 Warum API-Versionierung?

REST APIs sind oft ein zentraler Bestandteil von Microservices-Architekturen oder öffentlichen Schnittstellen für externe Entwickler und Systeme. Sobald eine API in Produktion geht, können Sie nicht davon ausgehen, dass alle Clients sofort auf die neueste Version wechseln. API-Versionierung bietet eine strukturierte Möglichkeit, Änderungen an der API vorzunehmen, ohne ältere Clients zu brechen.

48.1.1 Hauptgründe für API-Versionierung:

  1. Breaking Changes: Änderungen an der API, die inkompatibel mit vorherigen Versionen sind, erfordern eine neue Version.
  2. Neue Features: Einführung neuer Funktionen, die von bestimmten Clients nicht sofort unterstützt werden müssen.
  3. Deprecation und Migration: Planmäßige Abschaltung älterer Versionen und Einführung einer Übergangsphase für die Migration.

48.2 Ansätze zur API-Versionierung

Es gibt verschiedene Möglichkeiten, wie Sie die API-Versionierung in einer RESTful API umsetzen können:

  1. Pfadbasierte Versionierung: Die API-Version wird in der URL angegeben.
  2. Header-basierte Versionierung: Die API-Version wird über den HTTP-Header übermittelt.
  3. Parameterbasierte Versionierung: Die API-Version wird als URL-Parameter übergeben.

48.2.1 1. Pfadbasierte Versionierung

Die pfadbasierte Versionierung ist der einfachste und am häufigsten verwendete Ansatz. Die Versionsnummer wird Teil der URL.

48.2.1.1 Beispiel: Pfadbasierte Versionierung

@RestController
@RequestMapping("/api/v1/products")
public class ProductV1Controller {

    @GetMapping
    public String getProductsV1() {
        return "Produkte der API Version 1";
    }
}

@RestController
@RequestMapping("/api/v2/products")
public class ProductV2Controller {

    @GetMapping
    public String getProductsV2() {
        return "Produkte der API Version 2";
    }
}

In diesem Beispiel haben wir zwei Versionen des Endpunkts /products. Version 1 ist unter /api/v1/products erreichbar, während Version 2 unter /api/v2/products verfügbar ist. Dieser Ansatz ist einfach und klar, da die Version explizit in der URL steht.

48.2.2 2. Header-basierte Versionierung

Bei der header-basierten Versionierung wird die API-Version über einen speziellen HTTP-Header übermittelt, z.B. X-API-VERSION. Dieser Ansatz hält die URLs sauber und trennt die Versionierung von der Ressource selbst.

48.2.2.1 Beispiel: Header-basierte Versionierung

@RestController
public class ProductHeaderVersionController {

    @GetMapping("/products")
    @RequestMapping(headers = "X-API-VERSION=1")
    public String getProductsV1() {
        return "Produkte der API Version 1";
    }

    @GetMapping("/products")
    @RequestMapping(headers = "X-API-VERSION=2")
    public String getProductsV2() {
        return "Produkte der API Version 2";
    }
}

In diesem Beispiel wird die Version über den HTTP-Header X-API-VERSION gesteuert. Ein Client, der Version 1 der API verwenden möchte, muss den Header X-API-VERSION: 1 in seine Anfragen einfügen.

48.2.3 3. Parameterbasierte Versionierung

Bei der parameterbasierten Versionierung wird die API-Version als Query-Parameter übergeben.

48.2.3.1 Beispiel: Parameterbasierte Versionierung

@RestController
public class ProductParamVersionController {

    @GetMapping(value = "/products", params = "version=1")
    public String getProductsV1() {
        return "Produkte der API Version 1";
    }

    @GetMapping(value = "/products", params = "version=2")
    public String getProductsV2() {
        return "Produkte der API Version 2";
    }
}

In diesem Beispiel wird die Versionierung über einen Query-Parameter (version) durchgeführt. Der Client muss z.B. GET /products?version=1 an die API senden, um Version 1 der API zu verwenden.

48.3 Versionierung von Ressourcen

Nicht nur Endpunkte, sondern auch die Ressourcenstruktur oder das Datenmodell kann sich von Version zu Version ändern. Spring Boot ermöglicht es, verschiedene Versionen von DTOs oder Entitäten zu erstellen, die jeweils zu einer bestimmten API-Version passen.

48.3.1 Beispiel: Versionierte Ressourcen

// API Version 1
public class ProductV1 {
    private String name;
    // Getter und Setter
}

// API Version 2
public class ProductV2 {
    private String name;
    private String description; // Neue Eigenschaft in Version 2
    // Getter und Setter
}

In diesem Beispiel haben wir zwei Versionen des Product-Objekts: ProductV1 für die erste API-Version und ProductV2 für die zweite Version. Jede Version der API gibt das jeweilige Objekt zurück.

48.3.2 Beispiel: Controller mit versionierten Ressourcen

@RestController
@RequestMapping("/api/v2/products")
public class ProductV2Controller {

    @GetMapping
    public ProductV2 getProductV2() {
        return new ProductV2("Laptop", "Neues Modell mit erweiterten Funktionen");
    }
}

@RestController
@RequestMapping("/api/v1/products")
public class ProductV1Controller {

    @GetMapping
    public ProductV1 getProductV1() {
        return new ProductV1("Laptop");
    }
}

48.4 Best Practices für API-Versionierung

  1. Konsistenz: Wählen Sie eine Versionierungsstrategie (Pfad, Header oder Parameter) und bleiben Sie konsistent. Mischen Sie keine Versionierungsansätze.
  2. Versionierung nur bei Breaking Changes: Führen Sie neue API-Versionen nur ein, wenn dies erforderlich ist, z.B. bei Breaking Changes. Kleine Änderungen können oft rückwärtskompatibel sein.
  3. Deprecation und Unterstützung älterer Versionen: Stellen Sie sicher, dass Sie klare Richtlinien für die Einstellung veralteter API-Versionen haben. Benachrichtigen Sie die Benutzer rechtzeitig, bevor ältere Versionen abgeschaltet werden.
  4. Dokumentation: Dokumentieren Sie alle API-Versionen und die Änderungen zwischen den Versionen. Verwenden Sie Tools wie Swagger oder OpenAPI, um interaktive API-Dokumentationen bereitzustellen.

48.5 tl;dr

API-Versionierung ist ein unverzichtbares Konzept für die Entwicklung skalierbarer und wartbarer RESTful Webservices. Durch die Versionierung können Sie sicherstellen, dass Änderungen und Erweiterungen Ihrer API den Betrieb bestehender Clients nicht beeinträchtigen. Unabhängig davon, ob Sie sich für pfadbasierte, header-basierte oder parameterbasierte Versionierung entscheiden, ist es wichtig, konsistent zu bleiben und eine klare Migrationsstrategie zu haben. Mit den Tools und Funktionen von Spring Boot können Sie eine flexible und robuste Versionierung Ihrer REST-APIs implementieren.