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á.