Documentando APIs com Spring REST Docs: Snippets
Depois de concluirmos este webinar, nós:
- Saberemos como documentar diferentes códigos de status HTTP retornados por um mesmo endpoint.
- Compreenderemos como documentar os documentos JSON enviados no corpo da requisição para a nossa API REST.
- Saberemos documentar as respostas HTTP de sucesso e de erro de validação retornadas pela nossa API REST.
Este webinar assume que:
- Você sabe especificar o contexto de aplicação carregado pelo Spring TestContext Framework.
- Você está familiarizado com o JUnit 6.
- Você sabe criar um projeto que executa testes unitários, de integração e End-to-End com JUnit 6.
- Você sabe documentar uma API REST simples com o Spring REST Docs (Parte 1).
Introdução ao Sistema sob Teste
Durante este webinar, documentaremos um método controlador simples que processa requisições POST enviadas ao caminho /api/message. Este método lê as informações da mensagem criada a partir do corpo da requisição (@RequestBody), valida as informações da mensagem criada (@Valid) e retorna as informações da mensagem “criada” como JSON com status HTTP 201 (Created).
O código-fonte da classe MessageController em Kotlin é o seguinte:
|
|
A classe MessageDTO é um objeto de transferência de dados simples que contém as informações de uma única mensagem. Ela também garante (via Jakarta Bean Validation @field:NotBlank) que não podemos criar uma mensagem que tenha o texto em branco:
|
|
A seguir, descobriremos como podemos criar os snippets Asciidoctor necessários com o Spring REST Docs.
Criando os Snippets Asciidoctor Necessários com o Spring REST Docs
Podemos gerar os snippets Asciidoctor necessários com o Spring REST Docs seguindo quatro passos:
Primeiro, temos que criar uma nova classe de teste unitário (MessageControllerTest), configurar o Spring MVC Test framework no modo standalone (incluindo o ValidationErrorHandler em setControllerAdvice(...)) e integrar o Spring REST Docs com o MockMvc:
|
|
Nota: Este webinar descreve como criar os snippets Asciidoctor necessários escrevendo testes unitários, mas a mesma técnica funciona de maneira idêntica em testes de integração anotados com
@AutoConfigureRestDocs.
Segundo, temos que criar uma classe de teste interna @Nested chamada CreateNewMessage que conterá nossos casos de teste e a propriedade input do tipo MessageDTO.
Terceiro, temos que criar os snippets Asciidoctor que nos ajudam a documentar o que acontece quando tentamos criar uma nova mensagem que possui um texto de mensagem vazio (""). Fazemos isso seguindo estes passos:
- Criar uma classe interna
@NestedchamadaWhenEmptyMessageTextIsGiven. - Escrever um método
@BeforeEachque cria um novo objetoMessageDTO(text = ""). - Escrever um método de teste que envia a requisição
POST /api/messagee gera os snippets com.andDo(document("create-message-empty-text")).
Quarto, temos que criar os snippets Asciidoctor que nos ajudam a documentar o que acontece quando criamos uma nova mensagem usando informações válidas ("Hello World!"). Fazemos isso seguindo estes passos:
- Criar uma classe interna
@NestedchamadaWhenValidMessageTextIsGiven. - Escrever um método
@BeforeEachque cria um novo objetoMessageDTO(text = "Hello World!"). - Escrever um método de teste que envia a requisição
POST /api/messagee gera os snippets com.andDo(document("create-message-success")).
Após termos criado os dois conjuntos de snippets Asciidoctor, nossa classe de teste completa fica assim:
|
|
Atenção aos Identificadores de Recursos:
Quando especificamos os identificadores dos recursos documentados em
document(...), devemos usar identificadores únicos para cada caso de uso ("create-message-empty-text"e"create-message-success"). Se usássemos o mesmo nome nos dois testes, o segundo teste sobrescreveria os arquivos Asciidoctor do primeiro no mesmo diretório!
Vamos avançar e escrever o documento Asciidoctor que documenta nossa API REST.
Escrevendo a Documentação da Nossa API REST
Quando documentarmos nossa API REST, utilizaremos dois snippets gerados automaticamente pelo Spring REST Docs em cada diretório:
- O snippet
request-body.adocdescreve o corpo JSON da requisição HTTP enviada para a nossa API REST. - O snippet
http-response.adocdescreve a resposta HTTP completa (status, cabeçalhos e corpo JSON) retornada pela nossa API REST.
Podemos documentar nossa API REST seguindo estes passos:
Primeiro, documentamos o happy path (caminho feliz) do nosso recurso de API seguindo estes passos:
- Adicionar uma subseção chamada
Create Messageà seçãoResources. - Descrever como podemos criar uma nova mensagem e incluir o snippet
{snippets}/create-message-success/request-body.adoc[]. - Descrever os códigos de status HTTP suportados. É uma excelente ideia usar uma tabela Asciidoctor para esse propósito, pois ela oferece uma visão geral imediata dos códigos HTTP retornados pelo endpoint (
201e400). - Descrever a resposta HTTP retornada pelo nosso recurso de API quando a criação tem sucesso incluindo
{snippets}/create-message-success/http-response.adoc[].
Segundo, temos que descrever o que acontece se tentarmos criar uma nova mensagem usando informações inválidas. Fazemos isso adicionando uma subseção chamada Validation Errors dentro da seção Create Message, e documentamos cada erro de validação em sua própria subseção:
- Adicionar uma subseção chamada
Empty Message Textdentro da seçãoValidation Errors. - Descrever o documento JSON que dispara esse erro de validação (
{snippets}/create-message-empty-text/request-body.adoc[]). - Descrever a resposta HTTP de erro retornada pela nossa API REST (
{snippets}/create-message-empty-text/http-response.adoc[]).
Após termos descrito o caminho feliz e todos os erros de validação, a parte relevante do nosso documento Asciidoctor (index.adoc) fica assim:
|
|
Documentamos nossa API REST cobrindo tanto o fluxo de sucesso quanto os contratos de erro de validação! Vamos resumir o que aprendemos neste webinar.
Resumo
Este webinar nos ensinou cinco coisas:
- Se precisarmos documentar múltiplos casos de uso diferentes do mesmo recurso de API (ex.: sucesso
201e erro400), devemos garantir que cada caso de uso receba um identificador de recurso único no métododocument(...). - Podemos documentar o payload JSON enviado para a nossa API REST usando o snippet Asciidoctor
request-body.adoc. - É uma ótima prática documentar todos os códigos de status HTTP suportados pelo endpoint usando uma tabela Asciidoctor.
- Podemos documentar a resposta HTTP retornada pela nossa API REST usando o snippet Asciidoctor
http-response.adoc. - Devemos documentar todos os erros de validação usando uma subseção dedicada para cada regra de validação.