Neste post daremos continuidade a uma série de postagens sobre Web-Services divididos entre conceitos teóricos e praticos. Nos 3 primeiros posts focou-se em teoria com um sobre Web Services, outro sobre RESTful Web Services e mais um sobre os HTTP Status Codes mais comuns. Este post por sua vez complementa o que foi desenvolvido no post Do zero ao REST em 5 minutos com SpringBoot. Então antes de começar veja o post anterior ou baixe o código e vamos entender na prática como funcionam os verbos REST.
Agora faremos algumas alterações no projeto desenvolvido no post anterior. Para começar crie os seguintes pacotes br.com.erudio.models, br.com.erudio.services, br.com.erudio.services.implementations e br.com.erudio.web.controllers. Depois mova a classe Greeting para o pacote br.com.erudio.models e a classe GreetingController para o pacote br.com.erudio.web.controllers. A estrutura de pacotes deve ficar similar a imagem abaixo.
Feito isto crie uma classe chamada Person, no pacote br.com.erudio.models, com as informações que serão representadas pelo nosso endpoint REST.
package br.com.erudio.models;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Person implements Serializable{
private static final long serialVersionUID = 1L;
private Long id;
private String firstName;
private String lastName;
private String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Feito isto crie uma interface com o nome PersonService no pacote br.com.erudio.models.
package br.com.erudio.services;
import java.util.List;
import br.com.erudio.models.Person;
public interface PersonService {
Person create(final Person person);
Person findById(final String personId);
List<person> findAll();
Person update(Person person);
void delete(final String personId);
}
Agora vamos criar a implementação para a interface PersonService. No pacote br.com.erudio.services.implementations crie a classe PersonServiceImpl que implementa a interface que acabamos de criar.
package br.com.erudio.services.implementations;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.stereotype.Service;
import br.com.erudio.models.Person;
import br.com.erudio.services.PersonService;
@Service
public class PersonServiceImpl implements PersonService {
// Contador responsável por gerar um fake ID já que não estamos
// acessando nenhum banco de dados
private final AtomicLong counter = new AtomicLong();
// Metodo responsável por criar uma nova pessoa
// Se tivéssemos um banco de dados esse seria o
// momento de persistir os dados
@Override
public Person create(Person person) {
return person;
}
// Método responsável por retornar uma pessoa
// como não acessamos nenhuma base de dados
// estamos retornando um mock
@Override
public Person findById(String personId) {
Person person = new Person();
person.setId(counter.incrementAndGet());
person.setFirstName("Leandro");
person.setLastName("Costa");
person.setAddress("Uberlândia - Minas Gerais - Brasil");
return person;
}
// Método responsável por retornar todas as pessoas
// mais uma vez essas informações são mocks
@Override
public List<person> findAll() {
ArrayList<person> persons = new ArrayList<>();
for (int i = 0; i < 8; i++) {
Person person = mockPerson(i);
persons.add(person);
}
return persons;
}
// Método responsável por atualizar uma pessoa
// por ser mock retornamos a mesma informação passada
@Override
public Person update(Person person) {
return person;
}
// Método responsável por deletar
// uma pessoa a partir de um ID
@Override
public void delete(String personId) {
}
// Método responsável por mockar uma pessoa
private Person mockPerson(int i) {
Person person = new Person();
person.setId(counter.incrementAndGet());
person.setFirstName("Person Name " + i);
person.setLastName("Last Name " + i);
person.setAddress("Some Address in Brasil " + i);
return person;
}
}
Por fim crie a classe PersonController, responsável por expor o endpoint de pessoas, no pacote br.com.erudio.web.controllers.
package br.com.erudio.web.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import br.com.erudio.models.Person;
import br.com.erudio.services.PersonService;
@RestController
//Mapeia as requisições de localhost:8080/person/
@RequestMapping("/person/")
public class PersonController {
@Autowired
private PersonService personService;
@ResponseStatus(HttpStatus.OK) //Por padrão responde com o status code 200 success
@RequestMapping(value = "/{personId}",
//Mapeia as requisições GET para localhost:8080/person/
//recebendo um ID como @PathVariable
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
// Produz JSON como retorno
public Person get(@PathVariable(value = "personId") String personId){
return personService.findById(personId);
}
@ResponseStatus(HttpStatus.OK)
//Por padrão responde com o status code 200 success
@RequestMapping(value = "/findAll",
//Mapeia as requisições GET para localhost:8080/person/findAll
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
// Produz JSON como retorno
public List<person> findAll(){
return personService.findAll();
}
@ResponseStatus(HttpStatus.OK)
//Por padrão responde com o status code 200 success
@RequestMapping(method = RequestMethod.PUT,
//Mapeia as requisições PUT para localhost:8080/person/
consumes = MediaType.APPLICATION_JSON_VALUE,
// Consome JSON enviado no corpo da requisição
produces = MediaType.APPLICATION_JSON_VALUE)
// Produz JSON como retorno
public Person create(@RequestBody Person person){
return personService.create(person);
}
@ResponseStatus(HttpStatus.OK)
//Por padrão responde com o status code 200 success
@RequestMapping(method = RequestMethod.POST,
//Mapeia as requisições POST para localhost:8080/person/
consumes = MediaType.APPLICATION_JSON_VALUE)
// Consome JSON enviado no corpo da requisição
public Person update(@RequestBody Person person){
return personService.update(person);
}
@ResponseStatus(HttpStatus.OK)
//Por padrão responde com o status code 200 success
@RequestMapping(value = "/{personId}",
method = RequestMethod.DELETE)
//Mapeia as requisições DELETE para localhost:8080/person/
//recebendo um ID como @PathVariable
public void delete(@PathVariable(value = "personId") String personId){
personService.delete(personId);
}
}
Agora que terminamos nossa codificação acesse a classe Application e inicie a aplicação como no post anterior. Para testar nosso endpoint e cada uma de suas operações usaremos o plugin do Chrome Postman.
Primeiro faremos uma requisição do tipo GET chamando a operação findAll para o recurso localhost:8080/person/findAll. Como se pode ver na imagem abaixo obtemos como resposta um JSON com um array de pessoas.
Agora faremos uma requisição do tipo GET chamando a operação localhost:8080/person/1 passando como @PathVariable o ID da pessoa que desejamos recuperar. Da mesma forma que na requisição anterior recebemos como resposta um JSON com 1 objeto pessoa.
Agora faremos uma requisição do tipo POST (esse é o verbo REST usado para persistir informações) chamando a operação localhost:8080/person/ passando como parâmetro um JSON com um objeto pessoa no corpo da requisição. Para isso no Postman precisamos setar o tipo de requisição como POST, na aba Body definimos o JSON que representa o objeto pessoa a ser gravado, selecionamos a opção raw, definimos a opção JSON(application/json) e por fim executamos a request através do botão send.
Na imagem abaixo podemos ver o body da response retornada com um ID definido pela aplicação.
Agora faremos uma requisição do tipo PUT (esse é o verbo REST usado para atualizar informações) chamando a operação localhost:8080/person/ passando como parâmetro um JSON com um objeto pessoa no corpo da requisição. Lembrando que essa representação de pessoa deve ter um ID que será usado pra localizar e atualizar um recurso na base. Para isso no Postman precisamos setar informações similares ao post a unica diferença é que o tipo de requisição deve ser o PUT.
Como se pode ver na imagem abaixo o body da response retorna o nosso objeto JSON com as alterações.
Por fim faremos uma requisição do tipo DELETE (verbo REST usado excluir informações) chamando a operação localhost:8080/person/1 passando como @PathVariable o ID da pessoa que desejamos remover da base. Esse tipo de requisição retorna como resposta um body vazio e um StatusCode 200 caso a operação seja executada com sucesso os StatusCode 204 (no content), 401 (Unauthorized), 403 (forbiden), 404 (not found) ou 500 (internal server error) podem ser retornados.
Dessa forma abordamos os 4 verbos principais do HTTP usados em aplicações REST. Lembrando que você pode baixar o código aqui e descompactar o arquivo zip e importar não sua IDE de preferencia ou clonar usando Git:
git clone https://github.com/leandrocgsi/simple-rest-example-verbs.git
Continue ligado no blog, por que no próximo post iremos documentar a nossa API com o framewrok Swagger. E claro a abordagem nesses posts também será totalmente mão na massa. É isso aí bons estudos.
Treinamentos relacionados com este post















Cara show esses seus tutoriais, simples, práticos e eficaz!
Obrigado Bruno.
Olá Leandro, estou iniciando neste universo e estou fazendo testes com o código que tu disponibilizou. Quando eu testo o POST, me retorna o seguinte erro no Postman:
{
“timestamp”: 1572026545344,
“status”: 400,
“error”: “Bad Request”,
“exception”: “org.springframework.http.converter.HttpMessageNotReadableException”,
“message”: “Required request body is missing: public br.com.erudio.models.Person br.com.erudio.web.controllers.PersonController.create(br.com.erudio.models.Person)”,
“path”: “/person/”
}