Ein benutzerdefinierter Medientyp für eine Spring-REST-API

Ein benutzerdefinierter Medientyp für eine Spring REST-API

1. Überblick

In diesem Lernprogramm werden wir uns mit der Definition benutzerdefinierter Medientypen und deren Produktion durch den Spring REST-Controller befassen.

Ein guter Anwendungsfall für die Verwendung eines benutzerdefinierten Medientyps ist die Versionierung einer API.

2. API - Version 1

Beginnen wir mit einem einfachen Beispiel - einer API, die eine einzelne Ressource anhand ihrer ID verfügbar macht.

Wir beginnen mit einer Version 1 der Ressource, die wir dem Client zur Verfügung stellen. Zu diesem Zweck verwenden wir einen benutzerdefinierten HTTP-Header -“application/vnd.example.api.v1+json”.

Der Client fragt über den HeaderAcceptnach diesem benutzerdefinierten Medientyp.

Hier ist unser einfacher Endpunkt:

@RequestMapping(
  method = RequestMethod.GET,
  value = "/public/api/items/{id}",
  produces = "application/vnd.example.api.v1+json"
)
@ResponseBody
public exampleItem getItem( @PathVariable("id") String id ) {
    return new exampleItem("itemId1");
}

Beachten Sie hier den Parameterproduces, der den benutzerdefinierten Medientyp angibt, den diese API verarbeiten kann.

Nun dieexampleItem Ressource - die ein einzelnes Feld hat -itemId:

public class exampleItem {
    private String itemId;

    // standard getters and setters
}

Zu guter Letzt schreiben wir einen Integrationstest für den Endpunkt:

@Test
public void givenServiceEndpoint_whenGetRequestFirstAPIVersion_then200() {
    given()
      .accept("application/vnd.example.api.v1+json")
    .when()
      .get(URL_PREFIX + "/public/api/items/1")
    .then()
      .contentType(ContentType.JSON).and().statusCode(200);
}

3. API - Version 2

Nehmen wir nun an, wir müssen die Details ändern, die wir dem Kunden mit unserer Ressource zur Verfügung stellen.

Früher haben wir eine unformatierte ID verfügbar gemacht. Nehmen wir an, wir müssen diese jetzt ausblenden und stattdessen einen Namen verfügbar machen, um ein bisschen mehr Flexibilität zu erhalten.

Es ist wichtig zu verstehen, dass diese Änderung nicht abwärtskompatibel ist. Im Grunde ist es eine bahnbrechende Veränderung.

Hier ist unsere neue Ressourcendefinition:

public class exampleItemV2 {
    private String itemName;

    // standard getters and setters
}

Wir müssen hier also Folgendes tun: Migrieren Sie unsere API auf eine zweite Version.

Wir werden das umcreating the next version of our custom media type tun und einen neuen Endpunkt definieren:

@RequestMapping(
  method = RequestMethod.GET,
  value = "/public/api/items/{id}",
  produces = "application/vnd.example.api.v2+json"
)
@ResponseBody
public exampleItemV2 getItemSecondAPIVersion(@PathVariable("id") String id) {
    return new exampleItemV2("itemName");
}

Und so haben wir jetzt genau den gleichen Endpunkt, der aber in der Lage ist, die neue V2-Operation auszuführen.

Wenn der Client nach“application/vnd.example.api.v1+json” fragt, delegiert Spring an die alte Operation und der Client erhältexampleItem mit einemitemId-Feld (V1).

Wenn der Client jetzt den Header vonAcceptauf“application/vnd.example.api.v2+json” – setzt, trifft er die neue Operation korrekt und erhält die Ressource mit dem FelditemName (V2) zurück:

@Test
public void givenServiceEndpoint_whenGetRequestSecondAPIVersion_then200() {
    given()
      .accept("application/vnd.example.api.v2+json")
    .when()
      .get(URL_PREFIX + "/public/api/items/2")
    .then()
      .contentType(ContentType.JSON).and().statusCode(200);
}

Beachten Sie, wie ähnlich der Test ist, aber den unterschiedlichen HeaderAcceptverwendet.

4. Benutzerdefinierter Medientyp Auf Klassenebene

Lassen Sie uns abschließend über eine klassenweite Definition des Medientyps sprechen - das ist auch möglich:

@RestController
@RequestMapping(
  value = "/",
  produces = "application/vnd.example.api.v1+json"
)
public class CustomMediaTypeController

Wie erwartet funktioniert die Annotation@RequestMapping problemlos auf Klassenebene und ermöglicht die Angabe der Parametervalue,produces undconsumes.

5. Fazit

In diesem Artikel werden Beispiele zum Definieren benutzerdefinierter Medientypen veranschaulicht, die bei der Versionierung der öffentlichen API hilfreich sein können.

Die Implementierung all dieser Beispiele und Codefragmente finden Sie inthe GitHub project - dies ist ein Maven-Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.