Spring Web
Introdução
Implementar recursos HTTP para interação de arquivos JSON pelas aplicações.
O que é API
Uma API (interface application program) é um código programável que faz a “ponte” de comunicação entre duas aplicações distintas.
REST e RESTful
A API REST (representational state transfer) é como um guia de boas práticas e RESTful é a capacidade de determinado sistema aplicar os princípios de REST.
Princípios
Para que uma arquitetura seja RESTful, é necessário ter uma série de princípios ou padrões. Vejamos quais são eles:
- cliente-servidor — significa aprimorar a portabilidade entre várias plataformas de interface do usuário e do servidor, permitindo uma evolução independente do sistema;
- interface uniforme — representa uma interação uniforme entre cliente e servidor. Para isso, é preciso ter uma interface que identifique e represente recursos, mensagens autodescritivas, bem como hypermedia (HATEOAS);
- stateless — indica que cada interação via API tem acesso a dados completos e compreensíveis;
- cache — necessário para reduzir o tempo médio de resposta, melhorar a eficiência, desempenho e escalabilidade da comunicação;
- camadas — permite que a arquitetura seja menos complexa e altamente flexível.
Nível de Maturidade
Para padronizar e facilitar o desenvolvimento de APIs REST, Leonard Richardson propôs um modelo de maturidade para esse tipo de API, definido em 4 níveis.
Nível 0: Ausência de Regras
Esse é considerado o nível mais básico de uma API, quem implementa apenas esse nível não pode ser considerada REST pois não segue qualquer padrão.
Um único verbo com nomes que não seguem nenhum padrão
Nível 1: Aplicação de Resources
Observe que o nome dos recursos foram equalizados e para não gerar ambiguidade é necessário definir o verbo apropriadamente.
Nível 2: Implementação de verbos HTTP
Como a definição dos verbos já foi requisitada no Nível 1, o Nível 2 se encarrega de validar a aplicabilidade dos verbos para finalidades específicas como:
Nível 3: HATEOAS
HATEOAS significa Hypermedia as the Engine of Application State. Uma API que implementa esse nível fornece aos seus clientes links que indicarão como poderá ser feita a navegação entre seus recursos. Ou seja, quem for consumir a API precisará saber apenas a rota principal e a resposta dessa requisição terá todas as demais rotas possíveis.
No exemplo acima, podemos ver o resultado de uma API que implementa HATEAOS, veja que na resposta dessa API há uma coleção “links”, cada link aponta para uma rota dessa API. No caso desse exemplo, temos um link para a própria rota, um link para alterar um cliente e outra para exlcuir.
Springboot REST API
Se preferir criar um projeto Spring Boot do zero, acesse o Primeiro Projeto.
Ou simplesmente adicione o starter do spring-stater-web.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Criando nosso primeiro Controller
Um controller é um recurso que disponibiliza as funcionalidades de negócio da aplicação, através do protocolo HTTP. Vamos criar uma classe de exemplo:
Crie a classe WelcomeController.java
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;
@RestController
public class WelcomeController {
@GetMapping("/welcome")
public String welcome(){
return "Welcome to a Spring Boot REST API";
}
}
Inicialize a aplicação através da sua classe que contenha o método main e a anotação @SpringBootApplication.
o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
o.apache.catalina.core.StandardService : Starting service [Tomcat]
org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.52]
o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2240 ms
o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
d.a.AccessControlApplication : Started AccessControlApplication in 3.659
No navegador digite: http://localhost:8080/welcome
Primeiro Controller
Vamos criar nosso primeiro controller, para uma demonstração de uso de nossos serviços pela web.
Rest Controller
Um Rest Controller em Spring, nada mais é que uma classe contendo anotações específicas para a disponibilização de recursos HTTPs, baseados em nossos serviços e regras de negócio.
Anotações e configurações mais comuns:
- @RestController: Responsável por designar o bean de compoment, que surporta requisições HTTP com base na arquitetura REST.
- @RequestMapping("prefix"): Determina qual a URI comum para todos os recursos disponibilizados pelo Controller.
- @GetMapping: Determina que o método aceitará requisições HTTP do tipo GET.
- @PostMapping: Determina que o método aceitará requisições HTTP do tipo POST.
- @PutMapping: Determina que o método aceitará requisições HTTP do tipo PUT.
- @DeleteMapping: Determina que o método aceitará requisições HTTP do tipo DELETE.
- @RequestBody: Converte um JSON para o tipo do objeto esperado como parâmetro no método.
- @PathVariable: Consegue determinar que parte da URI será composta por parâmetros recebidos nas requisições.
Controle de Usuários
Vamos disponibilizar as funcionalidades de CRUD, da entidade User.java através de uma API:
public class Usuario {
private Integer id;
private String login;
private String password;
public Usuario() {}
public Usuario(String login, String password) {
this.login = login;
this.password = password;
}
@Override
public String toString() {
return "User{" +
"login='" + login + '\'' +
", password='" + password + '\'' +
'}';
}
... getters e setters
}
A classe UserRepository pode ser substituída pela implementação no tópico Spring Data Jpa.
@Repository
public class UserRepository {
public void save(Usuario usuario){
if(usuario.getId()==null)
System.out.println("SAVE - Recebendo o usuário na camada de repositório");
else
System.out.println("UPDATE - Recebendo o usuário na camada de repositório");
System.out.println(usuario);
}
public void deleteById(Integer id){
System.out.println(String.format("DELETE/id - Recebendo o id: %d para excluir um usuário", id));
System.out.println(id);
}
public List<Usuario> findAll(){
System.out.println("LIST - Listando os usários do sistema");
List<Usuario> usuarios = new ArrayList<>();
usuarios.add(new Usuario("gleyson","password"));
usuarios.add(new Usuario("frank","masterpass"));
return usuarios;
}
public Usuario findById(Integer id){
System.out.println(String.format("FIND/id - Recebendo o id: %d para localizar um usuário", id));
return new Usuario("gleyson","password");
}
public Usuario findByUsername(String username){
System.out.println(String.format("FIND/username - Recebendo o usernamae: %s para localizar um usuário", username));
return new Usuario("gleyson","password");
}
}
Confirme a existência do Starter Web no pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Primeiro criamos a classe controller UserController.java inserindo conforme código abaixo:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository repository;
@GetMapping
public List<User> list(){
return repository.findAll();
}
@PostMapping
public void save(@RequestBody User user){
repository.save(user);
}
@PutMapping
public void update(@RequestBody User user){
repository.save(user);
}
@GetMapping("/{username}")
public User find(@PathVariable("/username") String username){
return repository.findByUsername(username);
}
@DeleteMapping("/{id}")
public void delete(@PathVariable("/id") Integer id){
repository.deleteById(id);
}
}
Detalhando nosso código:
- Na linha 7: Definimos que nosso component é um REST Controller;
- Na linha 8: Podemos definir um sufixo para todos os nossos recursos HTTPs;
- Na linha 10: Realizamos a injeção de dependência do nosso UserRepository;
- Na linha 12: Temos um método GET/users para retornar todos os usuários;
- Na linha 16: Temos um método POST/users para salvar um novo usuário;
- Na linha 20: Temos um método PUT/users para alterar um usuário;
- Na linha 24: Temos um método GET/users/{username} para retornar um usuário pelo seu username;
- Na linha 28: Temos um método DELETE/users/{id} para remover um usuário pelo seu id.
Testando os serviços
O navegador consegue testar nossa aplicação somente com os métodos GET, mas como precisaremos realizar outros tipos de operações, será necessário ter um programa que interaja melhor com a API.
https://www.postman.com/downloads/
Após iniciar a aplicação Spring Boot, vamos incluir um usuário conforme requisição abaixo:
POST: http://localhost:8080/users
{"name":"GLEYSON SAMPAIO", "username":"glysns","password":"digytal@2021"}
Listando nossos usuários:
Alterando um usuário:
{
"id": 1,
"name": "GLEYSON SAMPAIO DE OLIVEIRA",
"username": "glysns",
"password": "digytal@2021"
}