Entre para a LISTA VIP da Black Friday

00

DIAS

00

HORAS

00

MIN

00

SEG

Clique para saber mais
Alura > Cursos de Programação > Cursos de Java > Conteúdos de Java > Primeiras aulas do curso Spring Boot 3: aplique boas práticas e proteja uma API Rest

Spring Boot 3: aplique boas práticas e proteja uma API Rest

Boas práticas na API - Apresentação

Boas-vindas ao curso de Spring Boot 3: aplique boas práticas e proteja uma API Rest!

Me chamo Rodrigo Ferreira e serei o seu instrutor ao longo deste curso, em que vamos aprender como usar as ferramentas do Spring Boot, sendo um framework do Java.

Rodrigo Ferreira é uma pessoa de pele clara, com olhos castanhos e cabelos castanhos e curto. Veste camiseta rosa lisa, e está sentado em uma cadeira preta. Ao fundo, há uma parede lisa com iluminação azul gradiente.

No curso anterior...

Este é o segundo curso, é importante que você tenha concluído o anterior Curso de Spring Boot 3: desenvolva uma API Rest em Java. Nele, iniciamos o projeto que daremos continuidade.

Recapitulando, no primeiro curso aprendemos como funciona o Spring Boot, a criar um projeto usando Spring initializr e começamos a desenvolver a API Rest.

No caso, fizemos o CRUD (Create, Read, Update e Delete), implementamos a funcionalidade de cadastro, listagem, remoção e atualização. Aprendemos, também, a fazer validações de formulários utilizando o bean validation. Por fim, focamos na paginação e ordenação.

Tudo isso foi desenvolvido no curso anterior, e a ideia deste presente curso é dar continuidade ao projeto iniciado. Partiremos do ponto que paramos no curso passado, e aprenderemos novos recursos do framework.

A seguir, vamos relembrar o layout do aplicativo mobile da nossa aplicação:

Protótipo do aplicativo que será trabalhado ao longo deste curso. Nele, há três telas mostradas lado a lado, da esquerda para direita. A primeira tela é a tela inicial, em que há a logo do aplicativo no canto superior direito. Abaixo há três botões retangulares grandes e azuis que ocupam o resto da tela para escolher as seções. De cima para baixo, a ordem dos botões é: Médicos(as), Pacientes e Consultas. A segunda tela é para pesquisar na seção escolhida anteriormente. No caso, mostra os resultados da seção "Médicos(as)". Se não houver um filtro, todos os resultados aparecerão em ordem alfabética. A terceira e última tela é um formulário de cadastro, com os campos a serem preenchidos. Os campos, de cima para baixo, são: Nome completo, especialidade, CRM, e-mail, telefone ou celular, logradouro, número, complemento e cidade.

Lembrando que focamos na parte de back-end, na API Rest, e continuaremos trabalhando nesse projeto da clínica médica. Desenvolvemos o CRUD de médicos e pacientes, e daremos prosseguimento neste curso.

Objetivos

Os objetivos deste segundo curso são: aprender boas práticas na API referente ao protocolo HTTP. Faremos ajustes na classe controller, para seguir as boas práticas do protocolo HTTP quanto ao retorno dos códigos HTTP e das respostas que a API devolve.

Logo após, realizaremos tratamento de erros. Eventualmente, pode ocorrer um erro na API, e precisamos entender o que o Spring faz ao ocorrer uma exception enquanto o programa é executado, o que é devolvido como resposta para o cliente da API.

Assim, vamos personalizar esses retornos para tratar esses erros da melhor forma possível.

Após isso, focaremos na segurança, no controle de autenticação e de autorização da API. No curso anterior não abordamos isso, logo a nossa API está pública - qualquer pessoa pode enviar requisições para remover, atualizar ou alterar informações da API.

Mas não é dessa forma que desejamos, precisamos ter um controle. Isso será feito na aplicação front-end, porém, na API precisamos ter um código que permite o usuário se autenticar, e também ter um controle de acesso de informações públicas e privadas.

Aprenderemos a aplicar isso com o Spring Security, sendo um módulo do Spring responsável por monitorar esse controle.

No caso, usaremos a autenticação fundamentada em tokens com o padrão JSON Web Token (JWT).

São esses os objetivos do segundo curso, focaremos em boas práticas, tratamento de erros e no controle de acesso, autenticação e autorização, usando tokens.

Gostou? Caso, sim, te espero na próxima aula!

Boas práticas na API - Padronizando retornos da API

Nesta aula faremos alguns ajustes no código do projeto, para melhorarmos algumas questões referentes às boas práticas.

No Insomnia, temos as requisições CRUD feitas na API, tanto de médicos quanto de pacientes. É justamente o que fizemos no curso anterior.

Pelo Insomnia disparamos as requisições para a API, isso para simular o aplicativo mobile ou aplicação front-end se comunicando com a API back-end.

Temos algumas considerações importantes: lembre-se que estamos desenvolvendo uma API Rest seguindo o protocolo HTTP. Logo, precisamos seguir às boas práticas relacionadas ao protocolo.

Uma dessas boas práticas já estamos aplicando: cada requisição que temos no Insomnia (excluir, atualizar, cadastrar e remover médico e pacientes), usamos os verbos do protocolo HTTP conforme a requisição.

Para excluir usamos o verbo delete, para cadastrar um médico ou paciente utilizamos o método post, para listar usamos o get e para atualizar utilizamos o put.

Porém, não são somente os verbos do protocolo HTTP e a URL que consideramos importantes, precisamos ter um tratamento do retorno da API nas requisições.

Por exemplo, na requisição DEL de excluir um médico do lado esquerdo do Insomnia. Perceba que a requisição disparará um método delete com a URL http://localhost:8080/medicos/2, sendo o ID 2.

Requisições no Insomnia:

DELExcluir Médico
PUTAtualizar Médico
GETListagem de médicos
POSTCadastro de Médico
POSTCadastro de Paciente
GETListagem de pacientes
PUTAtualizar Paciente
DELExcluir Paciente

Se clicarmos no botão "Send" para enviar à requisição, repare que ele nos devolve um código 200 OK, contido em uma caixa na cor verde, do lado direito. Isso significa que a requisição foi feita com sucesso.

O código 200 é o código do protocolo HTTP que significa "OK". No corpo da resposta, na aba "Preview", temos uma mensagem "No body returned for response" (em português, "Nenhum corpo retornou para resposta"). Está vazio.

Na requisição PUT de atualizar médico, temos algo semelhante:

PUT: http://localhost:8080/medicos

{
    "id": 2,
    "telefone": "1100009999"
}

Perceba que disparamos a requisição levando o JSON com os dados do médico que desejamos atualizar. Ao clicarmos no botão "Send", nos devolve o código 200 OK e com o corpo da resposta vazio. Igual ao caso anterior.

Será que precisamos retornar 200 em todas as requisições? Ou há outros códigos no protocolo HTTP mais adequados? É justamente nesse detalhe que faremos os ajustes.

O protocolo HTTP possui diversos códigos para vários cenários e não estamos usando esse recurso de forma adequada.

Estamos devolvendo 200 quando dá certo ("OK"), ou 500 que o Spring devolve de forma automática, ou erro 400 caso ocorra um erro de validação do bean validation.

Vamos analisar tudo isso no projeto.

Abriremos o IntelliJ, com o projeto já importado, sendo o mesmo que finalizamos no curso anterior. Do lado esquerdo, clicamos em "src > main > java > med.voll.api > controller > MedicoController".

Lembre-se que toda requisição chega no arquivo MedicoController.

Se analisarmos o método excluir, repare que colocamos o retorno como void.

//código omitido

 @DeleteMapping("/{id}")
 @Transactional
    public void excluir(@PathVariable Long id) {
        var medico = repository.getReferenceById(id);
        medico.excluir();
}

Não colocamos nenhum retorno no método de atualizar e de cadastrar. Devolvemos algo somente no método de listar, porque precisamos retornar algo, no caso, estamos usando a paginação do Spring Boot.

Porém, os outros métodos estão devolvendo um void. Isso é um problema!

Ao usarmos o void, não informamos o que o Spring precisa devolver. Por isso, por padrão, ele retorna o código 200 OK, se a requisição for processada com sucesso.

Porém, há outros códigos HTTP mais customizados dependendo do cenário. Por exemplo, no método excluir, o mais adequado seria devolver o código 204, que se refere à requisição processada e sem conteúdo.

Para devolver o código 204, começaremos a padronizar esses métodos. Ao invés de usarmos o void, utilizaremos uma classe do Spring chamada ResponseEntity, sendo uma classe que conseguimos controlar a resposta devolvida pelo framework.

// código omitido

 @DeleteMapping("/{id}")
 @Transactional
    public ResponseEntity excluir(@PathVariable Long id) {
        var medico = repository.getReferenceById(id);
        medico.excluir();
}

Assim, o retorno não será mais vazio ("void") e sim um objeto do tipo ResponseEntity. Esse método terá erro de compilação, ainda precisamos incluir o return.

Na última linha do método excluir, após a exclusão, adicionaremos o return. Contudo, como instanciamos o objeto ResponseEntity? Na classe ResponseEntity há métodos estáticos, que podemos usar neste caso.

Logo, colocaremos return ResponseEntity, sendo a classe, e digitamos um ponto ("."): return ResponseEntity..

Perceba que será exibido uma caixa com vários métodos que podemos devolver conforme o que desejamos, como ok, badRequest, noContent, notFound, etc.

Clicaremos no método noContent para o método excluir, com isso, ficaremos com: return ResponseEntity.noContent();.

Perceba que aparece um sublinhado na cor vermelha no retorno, isso significa que o método noContent não devolve um ResponseEntity. Na sequência, chamaremos o .build().

// código omitido

return ResponseEntity.noContent().build();

O noContent() cria um objeto e chamamos o build() para construir o objeto ResponseEntity.

//código omitido

@DeleteMapping("/{id}")
@Transactional
    public ResponseEntity excluir(@PathVariable Long id) {
        var medico = repository.getReferenceById(id);
        medico.excluir();

        return ResponseEntity.noContent().build();
    }

Podemos salvar clicando em "Ctrl + S".

Agora, voltaremos à Insomnia para enviarmos uma requisição para excluir um médico. Ele nos devolvia o código 200 OK, como podemos visualizar no lado direito.

Ao dispararmos a requisição clicando no botão "Send", o código se torna 204 No Content. Colocando o mouse por cima, é exibida uma mensagem explicando o que significa esse código.

Esse erro faz parte da categoria 200, que são os códigos de requisição que obtiveram sucesso, porém, é específico. O `204 No Content' significa que foi processado com sucesso, mas não possui conteúdo para ser mostrado na resposta.

Para remover, essa é uma boa prática, usar o código 204 e não o 200. Faremos essa mesma alteração nos outros métodos do arquivo MedicoController, para padronizarmos o controller e termos todos os métodos retornando um objeto ResponseEntity.

Nos métodos atualizar, cadastrar e listagem, alteramos de void para ResponseEntity.

Método atualizar

//código omitido

@PutMapping
@Transactional
public ResponseEntity atualizar(@RequestBody @Valid DadosAtualizacaoMedico dados) {
        var medico = repository.getReferenceById(dados.id());
        medico.atualizarInformacoes(dados);
    }

Método cadastrar

//código omitido

@PostMapping
@Transactional
public ResponseEntity cadastrar(@RequestBody @Valid DadosCadastroMedico dados) {
        repository.save(new Medico(dados));
}

No método de listar, incluiremos o ResponseEntity e no Page<DadosListagemMedico>, colocaremos mais um "<>" mas entre o page e o DadosListagemMedico: public <Page<DadosListagemMedico>>.

Método listagem

//código omitido

@GetMapping
public ResponseEntity<Page<DadosListagemMedico>> listar(@PageableDefault(size = 10, sort = {"nome"}) Pageable paginacao) {
   return repository.findAllByAtivoTrue(paginacao).map(DadosListagemMedico::new);
    }

Vamos padronizar, todos os métodos usaram a classe ResponseEntity do Spring Boot.

Como esperado, será exibido o erro de compilação (sublinhado na cor vermelha do método), isso acontece porque precisamos alterar para devolver o objeto ResponseEntity. Faremos esses ajustes agora.

No método de listar, alteramos o return. Isto é, ele não devolverá diretamente o page e vamos colocar o repository.findAllByAtivoTrue(paginacao) em uma variável chamada page.

//código omitido

@GetMapping
public ResponseEntity<Page<DadosListagemMedico>> listar(@PageableDefault(size = 10, sort = {"nome"}) Pageable paginacao) {
        var page = repository.findAllByAtivoTrue(paginacao).map(DadosListagemMedico::new);
    }

//código omitido

Na linha seguinte, faremos o return ResponseEntity.ok(), porque queremos devolver o código 200. No parênteses do ok(), passamos o objeto "page".

//código omitido

@GetMapping
public ResponseEntity<Page<DadosListagemMedico>> listar(@PageableDefault(size = 10, sort = {"nome"}) Pageable paginacao) {
        var page = repository.findAllByAtivoTrue(paginacao).map(DadosListagemMedico::new);
        return ResponseEntity.ok(page);
    }

//código omitido

Com isso, no método de listar será devolvido o código 200, e junto na resposta vem o objeto de paginação com os dados dos médicos.

Nos métodos de cadastrar e atualizar, como funcionaria?

Analisaremos, primeiro, o método atualizar.

Método atualizar

//código omitido

@PutMapping
@Transactional
public ResponseEntity atualizar(@RequestBody @Valid DadosAtualizacaoMedico dados) {
        var medico = repository.getReferenceById(dados.id());
        medico.atualizarInformacoes(dados);
    }

//código omitido

Neste método, usávamos void, ou seja, não tínhamos retorno nenhum. Porém, diferente do método de excluir, no de atualizar não podemos devolver um código 204.

O mais interessante no método de atualizar é devolver a informação atualizada. Como é para atualizar o registro do médico, no final devolveremos os dados do médico atualizado.

No final do método digitaremos return ResponseEntity.ok() e dentro dos parênteses precisamos passar o objeto.

Contudo, não podemos passar o objeto médico, porque é uma entidade JPA ("Java Persistence API") e não é recomendado devolver e receber entidades JPA no controller.

Logo, precisamos devolver um DTO ("Data Transfer Object"). Por exemplo, temos o DadosAtualizacaoMedico que é o nosso DTO. Clicando em "DadosAtualizacaoMedico", conseguimos visualizar o código.

Porém, esse DTO está incompleto, ele possui somente o id, nome, telefone e endereço. Sendo o DTO que representa os dados da atualização de um médico, isto é, os dados que o aplicativo mobile enviará para atualizar as informações.

No caso, queremos devolver todas as informações do médico. Por isso, criaremos outro DTO para representar esses dados do médico que estão sendo atualizados.

Voltando ao arquivo MedicoController, dentro do parênteses do ok.() colocaremos new DadosDetalhamentoMedico(). Agora, sim, passamos o objeto médico: new DadosDetalhamentoMedico(medico).

//código omitido

@PutMapping
@Transactional
public ResponseEntity atualizar(@RequestBody @Valid DadosAtualizacaoMedico dados) {
        var medico = repository.getReferenceById(dados.id());
        medico.atualizarInformacoes(dados);

        return ResponseEntity.ok(new DadosDetalhamentoMedico(medico));
    }

//código omitido

Perceba que DadosDetalhamentoMedico está escrito em uma cor vermelha bem forte, isso significa que ocorreu erro de compilação. Para ajustar isso, selecionaremos "Alt + Enter" no teclado, será exibido um pop-up com diversas opções, escolheremos a "Create record 'DadosDetalhamentoMedico'". Isso para ele criar esse DTO para nós.

Na caixa exibida, temos o título "Create Record DadosDetalhamentoMedico", com os campos "Destination package" e "Target destination directory".

No primeiro campo "Destination package" consta "med.voll.api.controller", alteraremos para "med.voll.api.medico", para mudar o pacote. Logo após, clicaremos no botão "Ok", no canto inferior direito.

Será criado o arquivo DadosDetalhamentoMedico:

package med.voll.api.medico;

public record DadosDetalhamentoMedico(Medico medico) {

}

Porém, teremos um record não recebendo o objeto médico e sim as informações do médico.

package med.voll.api.medico;

public record DadosDetalhamentoMedico(Long id, String nome, String email, String crm, String telefone, Especialidade especialidade, Endereco endereco) {

}

No método estamos instanciando um objeto médico, logo podemos criar um construtor que recebe um objeto do tipo medico. Esse construtor chama o construtor principal do record passando os parâmetros.

package med.voll.api.medico;

import med.voll.api.endereco.Endereco;

public record DadosDetalhamentoMedico(Long id, String nome, String email, String crm, String telefone, Especialidade especialidade, Endereco endereco) {
        public DadosDetalhamentoMedico (Medico medico) {
            this(medico.getId(), medico.getNome(), medico.getEmail(), medico.getCrm(), medico.getTelefone(), medico.getEspecialidade(), medico.getEndereco());

        }
}

Com isso, temos o record que recebe como parâmetro os dados do médico, e um construtor para passarmos o médico como parâmetro, que será usado no controller.

O método de cadastrar será um pouco diferente, porque existe o código 201 do protocolo HTTP que significa que a requisição foi processada e o novo recurso foi criado. Esse código possui um tratamento especial.

E usaremos o objeto DadosDetalhamentoMedico. Inclusive, podemos criar um novo endpoint (ou método) no controller, dado que temos somente os quatro métodos do CRUD (Create, Read, Update e Delete). Porém, faltou o método para detalhar.

Na listagem estamos devolvendo somente algumas informações dos médicos, mas e se quisermos detalhar trazendo todos os dados de um médico específico? Faltou esse método no controller.

No método de cadastrar, usaremos o código HTTP 201, o mais adequado. E usaremos esse DTO, também.

Mas aprenderemos isso na sequência. Te espero na próxima aula!

Boas práticas na API - Devolvendo o código HTTP 201

Na aula anterior, começamos a realizar as alterações no controller, nos métodos de excluir, atualizar e listar, para padronizar os retornos para responder ResponseEntity. No entanto, faltou o método cadastrar.

O método de cadastrar possui um detalhe a mais devido ao protocolo HTTP, e faremos mais uma requisição para detalhar o médico.

Conforme o protocolo HTTP, ao cadastrarmos uma informação ou recurso em uma API, o código HTTP que deve ser devolvido, neste cenário, é o código 201 chamado created. Esse código significa que um registro foi criado na API.

Código 201: devolve no corpo da resposta os dados do novo recurso/registro criado e um cabeçalho do protocolo HTTP (Location).

Porém, esse código 201 possui algumas regras. Na resposta, devemos colocar o código 201 e no corpo da resposta os dados do novo registro criado e, também, um cabeçalho do protocolo HTTP.

Esse cabeçalho mostra o endereço para que o front-end, ou aplicativo mobile consiga acessar o recurso cadastrado. Logo, no cadastro não devolvemos apenas o código 200 OK e nem apenas o 201.

Precisa ser o código 201, com os dados no formato JSON e um cabeçalho, na resposta. Para fazer isso, usaremos alguns recursos do Spring Boot.

//código omitido

@PostMapping
@Transactional
public ResponseEntity cadastrar(@RequestBody @Valid DadosCadastroMedico dados) {
        repository.save(new Medico(dados));
}

//código omitido

No método de cadastrar do arquivo MedicoController, note que ele já aponta um erro de compilação, já que alteramos o retorno de void para ResponseEntity.

Após chamarmos o repository.save, como fazemos para acionar o código 201? Incluiremos return ResponseEntity com o método .created(), que passaremos como parâmetro a uri: return ResponseEntity.created(uri).

Essa uri representa o endereço, e o Spring cria o cabeçalho location de forma automática conforme a uri que passamos como parâmetro. Ainda vamos criar essa URI.

//código omitido

@PostMapping
@Transactional
public ResponseEntity cadastrar(@RequestBody @Valid DadosCadastroMedico dados) {
        repository.save(new Medico(dados));

                return ResponseEntity.created(uri)
}

//código omitido

Na sequência colocamos .body(), para incluir as informações que queremos devolver no corpo da resposta, como parâmetro colocamos dto. Assim, ele cria o objeto ResponseEntity.

//código omitido

@PostMapping
@Transactional
public ResponseEntity cadastrar(@RequestBody @Valid DadosCadastroMedico dados) {
        repository.save(new Medico(dados));

                return ResponseEntity.created(uri).body(dto);
}

//código omitido

Temos o erro de compilação em uri e dto, isso porque essas variáveis não existem neste método cadastrar.

Para criarmos o objeto uri, na linha de cima do return, vamos criar a variável, var uri =. A URI deve ser o endereço da API, no caso é o http://localhost:8080/medicos/id, sendo o ID do médico que acabou de ser criado no banco de dados.

Lembrando que está rodando local e ainda faremos o deploy para rodar no servidor. Logo, não será mais http://localhost:8080, será alterado.

Para não precisarmos ter que dar muita atenção para esse ponto no controller, o Spring possui uma classe que encapsula o endereço da API. Essa classe realiza a construção da URI de forma automática.

Para usarmos essa classe, incluiremos mais um parâmetro no método cadastrar.

Atualmente, estamos recebendo o DadosCadastroMedico. Colocaremos uma vírgula (",") e, na sequência, um objeto do tipo UriComponentsBuilder, sendo a classe que gera a URI. Chamaremos essa classe de uriBuilder.

//código omitido

@PostMapping
@Transactional
public ResponseEntity cadastrar(@RequestBody @Valid DadosCadastroMedico dados, UriComponentsBuilder uriBuilder) {
        repository.save(new Medico(dados));

                var uri =

                return ResponseEntity.created(uri).body(dto);
}

//código omitido

Basta recebermos a classe como parâmetro no método controller, que o Spring fica responsável por passar esse parâmetro de forma automática.

Voltando para a variável uri, após o sinal de igual podemos colocar uriBuilder., e chamaremos o método path para passarmos o complemento da URL: var uri = uriBuilder.path(). Isso porque ele cria somente a URI localhost:8080, e precisamos incluir o complemento /medicos/id.

Portanto, no parênteses do método path vamos passar "/medicos/{id}". O id entre chaves é um parâmetro dinâmico.

//código omitido

@PostMapping
@Transactional
public ResponseEntity cadastrar(@RequestBody @Valid DadosCadastroMedico dados, UriComponentsBuilder uriBuilder) {
        repository.save(new Medico(dados));

                var uri = uriBuilder.path("/medicos/{id}")

                return ResponseEntity.created(uri).body(dto);
}

//código omitido

Perceba que é semelhante ao que fizemos no método de excluir: @DeleteMapping("/{id}"). O Spring sabe que o /{id} é um parâmetro dinâmico.

Voltando ao método de cadastrar, na sequência do path, precisamos substituir esse ID pelo ID do médico que foi criado no banco de dados.

Para isso, digitamos .buildAndExpand(). Nele, precisamos passar, como parâmetro, o ID do médico criado no banco de dados. Esse ID está na linha anterior, no repository.save que chamamos para salvar no banco de dados.

repository.save(new Medico(dados));

Contudo, passamos como parâmetro o new Medico para o método save. Vamos precisar desse médico na linha seguinte, por isso, criaremos uma variável para o médico: var medico =.

Em seguida, vamos extrair a linha que estamos passando como parâmetro para o método save e colaremos na variável medico.

var medico = new Medico(dados)
repository.save();

No repository.save() passamos o medico como parâmetro, e no buildAndExpand() o medico.getId(). O ID será gerado pelo banco de dados na linha anterior de forma automática. Logo após o build and expand, colocamos .toUri() para criar o objeto URI.

//código omitido

@PostMapping
@Transactional
public ResponseEntity cadastrar(@RequestBody @Valid DadosCadastroMedico dados, UriComponentsBuilder uriBuilder) {
                var medico = new Medico(dados)
                repository.save(medico);

                var uri = uriBuilder.path("/medicos/{id}").buildAndExpand(medico.getId()).toUri();

                return ResponseEntity.created(uri).body(dto);
}

//código omitido

Criamos o objeto URI. Agora, no return, perceba que o parâmetro dto está na cor vermelha, significa que precisamos criá-lo. Usaremos o mesmo dto que utilizamos no método de atualizar, o new DadosDetalhamentoMedico(medico).

Copiaremos esse método e colaremos no parâmetro do método .body()..

return ResponseEntity.created(uri).body(new DadosDetalhamentoMedico(medico));

Dessa forma, temos:

//código omitido

@PostMapping
@Transactional
public ResponseEntity cadastrar(@RequestBody @Valid DadosCadastroMedico dados, UriComponentsBuilder uriBuilder) {
                var medico = new Medico(dados)
                repository.save(medico);

                var uri = uriBuilder.path("/medicos/{id}").buildAndExpand(medico.getId()).toUri();

                return ResponseEntity.created(uri).body(new DadosDetalhamentoMedico(medico));
}

//código omitido

O método de cadastrar possui diversos detalhes, porque precisamos devolver o código 201, o cabeçalho location com a URI e no corpo da resposta é necessário ter uma representação do recurso recém criado.

Agora, vamos testar o cadastro, listagem, atualização e exclusão!

Alteramos para retornar o ResponseEntity nos métodos e salvamos essas modificações. Como o projeto já estava sendo executado, ele detecta as alterações de forma automática devido ao DevTools.

Voltando ao Insomnia, no método excluir médico, clicaremos no botão "Send" para disparar a requisição. Note que retornou o código 204 No Content, deu certo.

Agora, clicamos do lado esquerdo do IntelliJ em "PUT atualizar médido". Neste método, alteraremos no corpo do JSON o ID de "2" para "1", porque desejamos atualizar o médico que contém o ID 1 e o telefone:

PUT: http://localhost:8080/medicos

{
    "id": 1,
    "telefone": "2111112222"
}

Logo após, clicamos no botão "Send". Antes nos devolvia o código 200 OK, sem um corpo no retorno. Agora, temos o código 200 OK, mas com o seguinte corpo na resposta:

Preview

{
        "id": 1,
        "nome": "Rodrigo Ferreira",
        "email": "rodrigo.ferreira@voll.med",
        "crm": "123456",
        "telefone": "2111112222",
        "especialidade": "ORTOPEDIA",
        "endereco": {
            "logradouro": "rua 1",
            "bairro": "bairro",
            "cep": "12345678",
            "numero": "1",
            "complemento": null,
            "cidade": "Brasil",
            "uf": "DF"
        }
}

Esses são os dados atualizados do médico. Perceba que retorna todos os dados, não somente o id e o telefone - que foram os que alteramos.

Do lado esquerdo do IntelliJ, selecionaremos "GET Listagem de médicos" e depois o botão "Send". Perceba que este método não mudou, continua devolvendo o código 200 OK com JSON no corpo da resposta com os dados da paginação.

Ou seja, alteramos para ResponseEntity mas não alterou nada. Isso era esperado.

Vamos verificar se foi feita a alteração no cadastro. Para isso, clicaremos em "POST Cadastro de Médico" e no JSON, alteraremos os campos com as informações do "Renato" para "Juliana Queiroz".

Antes:

{
        "nome": "Renato Amoedo",
        "email": "renato.amoedo@voll.med",
        "crm": "233444",
        "telefone": "61999998888",
        "especialidade": "ORTOPEDIA",
        "endereco": {
            "logradouro": "rua 1",
            "bairro": "bairro",
            "cep": "12345678",
            "complemento": null,
            "cidade": "Brasil",
            "uf": "DF"
        }
}

Depois

{
        "nome": "Juliana Queiroz",
        "email": "juliana.queiroz@voll.med",
        "crm": "233444",
        "telefone": "61999998888",
        "especialidade": "ORTOPEDIA",
        "endereco": {
            "logradouro": "rua 1",
            "bairro": "bairro",
            "cep": "12345678",
            "complemento": null,
            "cidade": "Brasil",
            "uf": "DF"
        }
}

Após essas alterações, clicamos no botão "Send". Antes o código estava 500 Internal Server Error, agora está como 201 Created, com as seguintes informações no corpo da resposta em formato JSON:

{
        "id": 6,
        "nome": "Juliana Queiroz",
        "email": "juliana.queiroz@voll.med",
        "crm": "233444",
        "telefone": "2111112222",
        "especialidade": "ORTOPEDIA",
        "endereco": {
            "logradouro": "rua 1",
            "bairro": "bairro",
            "cep": "12345678",
            "numero": null,
            "complemento": null,
            "cidade": "Brasil",
            "uf": "DF"
        }
}

Do lado direito da aba "Preview", temos a aba "Header", sendo os cabeçalhos que foram devolvidos. Ao clicarmos na aba "Header", temos:

NameValue
Locationhttp://localhost:8080/medicos/6
Content-Typeapplication/json
Transfer-Encodingchunked
DateThu, 20 Oct 2022 19:49:00 GMT

Dessa forma, temos o cabeçalho location com o endereço http://localhost:8080/medicos/6, sendo o número 6 o ID do médico que acabamos de cadastrar no banco de dados.

Se tentarmos entrar no endereço /medicos/6, será devolvido o código 404. Isso porque não configuramos uma requisição para detalhar os dados de um médico.

Por enquanto, temos somente o CRUD (Create, Read, Update e Delete), mas em uma API geralmente temos uma quinta funcionalidade para detalhar as informações de um médico.

Na próxima aula, vamos aprender a criar essa funcionalidade.

Te espero no próximo vídeo!

Sobre o curso Spring Boot 3: aplique boas práticas e proteja uma API Rest

O curso Spring Boot 3: aplique boas práticas e proteja uma API Rest possui 255 minutos de vídeos, em um total de 60 atividades. Gostou? Conheça nossos outros cursos de Java em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Java acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas