Um tipo de mídia personalizado para uma API REST do Spring

Um tipo de mídia personalizado para uma API REST do Spring

1. Visão geral

Neste tutorial, veremos como definir tipos de mídia personalizados e produzi-los pelo controlador Spring REST.

Um bom caso de uso para usar o tipo de mídia personalizado é a versão de uma API.

2. API - Versão 1

Vamos começar com um exemplo simples - uma API expondo um único Recurso por id.

Vamos começar com uma versão 1 do recurso que estamos expondo ao cliente. Para fazer isso, vamos usar um cabeçalho HTTP personalizado -“application/vnd.example.api.v1+json”.

O cliente solicitará esse tipo de mídia personalizado por meio do cabeçalhoAccept.

Este é o nosso ponto final simples:

@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");
}

Observe o parâmetroproduces aqui - especificando o tipo de mídia personalizado que esta API pode manipular.

Agora, o recursoexampleItem - que tem um único campo -itemId:

public class exampleItem {
    private String itemId;

    // standard getters and setters
}

Por último, mas não menos importante, vamos escrever um teste de integração para endpoint:

@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 - versão 2

Agora vamos supor que precisamos mudar os detalhes que estamos expondo ao cliente com nosso Recurso.

Costumávamos expor um id bruto - digamos que agora precisamos ocultar isso e expor um nome, para obter um pouco mais de flexibilidade.

É importante entender que essa mudança não é compatível com versões anteriores; basicamente - é uma mudança significativa.

Aqui está nossa nova definição de recurso:

public class exampleItemV2 {
    private String itemName;

    // standard getters and setters
}

E então, o que precisamos fazer aqui é - migrar nossa API para uma segunda versão.

Faremos isso porcreating the next version of our custom media typee definiremos um novo endpoint:

@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");
}

E agora temos o mesmo ponto final exato, mas capaz de lidar com a nova operação V2.

Quando o cliente solicitar“application/vnd.example.api.v1+json” - o Spring delegará para a operação antiga e o cliente receberá umexampleItem com um campoitemId (V1).

Mas quando o cliente agora definir o cabeçalhoAccept para“application/vnd.example.api.v2+json” –, ele acertará corretamente a nova operação e receberá de volta o Recurso com o campoitemName (V2):

@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);
}

Observe como o teste é semelhante, mas está usando o cabeçalhoAccept diferente.

4. Tipo de mídia personalizado no nível da classe

Finalmente, vamos falar sobre uma definição para toda a classe do tipo de mídia - isso também é possível:

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

Como esperado, a anotação@RequestMapping funciona facilmente no nível da classe e nos permite especificar os parâmetrosvalue,produceseconsumes.

5. Conclusão

Este artigo ilustrou exemplos ao definir tipos de mídia personalizados que podem ser úteis na versão da API pública.

A implementação de todos esses exemplos e trechos de código pode ser encontrada emthe GitHub project - este é um projeto Maven, portanto, deve ser fácil de importar e executar como está.