Skip to the content.

Este guia fornecerá todos os conceitos e códigos completos para que os alunos possam expor a inteligência do sistema para o mundo exterior de forma padronizada e profissional.

💎 Guia Didático Definitivo: Gestão de Estoques com Spring Boot


Módulo 3: 🔌 Construindo a API REST

Objetivo: Expor a lógica de negócio, que criamos no Módulo 2, através de endpoints HTTP. Ao final deste módulo, o aluno terá uma API REST completamente funcional, capaz de realizar todas as operações de CRUD (Create, Read, Update, Delete), pronta para ser consumida por qualquer cliente (como um frontend SPA ou um aplicativo mobile).


### Aula 3.1: Introdução a APIs REST e @RestController

Conceito-Chave: API REST (Representational State Transfer) Pense em uma API REST como um “garçom” para a sua aplicação. O cliente (frontend) faz um pedido (requisição HTTP) para um “prato” específico (um recurso, como /produtos), e o garçom (a API) vai até a cozinha (a camada de serviço) e traz de volta o que foi pedido (uma representação do recurso, geralmente em formato JSON).

As principais regras são:

  1. Comunicação Cliente-Servidor: São sistemas separados.
  2. Stateless: O servidor não guarda informações sobre o cliente entre as requisições.
  3. Recursos: Tudo é um recurso, identificado por uma URL (ex: /api/produtos/1).

Conceito-Chave: @RestController No Spring, esta anotação é um atalho poderoso. Ela combina duas outras anotações:

Ação: Crie o pacote br.com.aula.gestaodeestoques.controller. É aqui que nossos “garçons” irão morar.


### Aula 3.2: Mapeando Verbos HTTP para Operações de CRUD

Conceito-Chave: O REST utiliza os verbos (métodos) do protocolo HTTP para indicar a intenção da operação sobre um recurso.

Verbo HTTP Operação CRUD Exemplo de Endpoint Descrição
GET Read /api/produtos Busca uma lista de todos os produtos.
GET Read /api/produtos/{id} Busca um único produto pelo seu ID.
POST Create /api/produtos Cria um novo produto.
PUT Update /api/produtos/{id} Atualiza um produto existente pelo seu ID.
DELETE Delete /api/produtos/{id} Deleta um produto existente pelo seu ID.

O Spring nos dá anotações diretas para mapear cada um desses verbos:


### Aula 3.3: Manipulando Respostas HTTP com ResponseEntity

Conceito-Chave: Uma resposta HTTP não é apenas o dado (o corpo JSON), mas também um Status Code que informa ao cliente o resultado da operação. O ResponseEntity é uma classe do Spring que nos dá controle total sobre a resposta.

Status Codes mais comuns em APIs REST:


### Aula 3.4: Implementando os Controllers

Ação: Agora vamos juntar todos os conceitos e criar os controllers para nossas entidades. Eles irão injetar e utilizar as interfaces de serviço que criamos no Módulo 2.

Código: controller/CategoriaController.java

package br.com.aula.gestaodeestoques.controller;

import br.com.aula.gestaodeestoques.dto.CategoriaDTO;
import br.com.aula.gestaodeestoques.service.CategoriaService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.net.URI;
import java.util.List;

@RestController
@RequestMapping("/api/categorias")
public class CategoriaController {

    @Autowired
    private CategoriaService service;

    @GetMapping
    public ResponseEntity<List<CategoriaDTO>> findAll() {
        List<CategoriaDTO> list = service.findAll();
        return ResponseEntity.ok(list);
    }

    @GetMapping("/{id}")
    public ResponseEntity<CategoriaDTO> findById(@PathVariable Integer id) {
        CategoriaDTO dto = service.findById(id);
        return ResponseEntity.ok(dto);
    }

    @PostMapping
    public ResponseEntity<CategoriaDTO> create(@Valid @RequestBody CategoriaDTO categoriaDTO) {
        CategoriaDTO newDto = service.create(categoriaDTO);
        URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
                .buildAndExpand(newDto.id()).toUri();
        return ResponseEntity.created(uri).body(newDto);
    }

    @PutMapping("/{id}")
    public ResponseEntity<CategoriaDTO> update(@PathVariable Integer id, @Valid @RequestBody CategoriaDTO categoriaDTO) {
        CategoriaDTO updatedDto = service.update(id, categoriaDTO);
        return ResponseEntity.ok(updatedDto);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable Integer id) {
        service.delete(id);
        return ResponseEntity.noContent().build();
    }
}

Código: controller/FornecedorController.java

package br.com.aula.gestaodeestoques.controller;

import br.com.aula.gestaodeestoques.dto.FornecedorDTO;
import br.com.aula.gestaodeestoques.service.FornecedorService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.net.URI;
import java.util.List;

@RestController
@RequestMapping("/api/fornecedores")
public class FornecedorController {

    @Autowired
    private FornecedorService service;

    @GetMapping
    public ResponseEntity<List<FornecedorDTO>> findAll() {
        return ResponseEntity.ok(service.findAll());
    }

    @PostMapping
    public ResponseEntity<FornecedorDTO> create(@Valid @RequestBody FornecedorDTO fornecedorDTO) {
        FornecedorDTO newDto = service.create(fornecedorDTO);
        URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
                .buildAndExpand(newDto.id()).toUri();
        return ResponseEntity.created(uri).body(newDto);
    }

    // ... Implementar outros endpoints (findById, update, delete) seguindo o padrão acima ...
}

Código: controller/ProdutoController.java

package br.com.aula.gestaodeestoques.controller;

import br.com.aula.gestaodeestoques.dto.ProdutoDTO;
import br.com.aula.gestaodeestoques.dto.ProdutoFormDTO;
import br.com.aula.gestaodeestoques.service.ProdutoService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.net.URI;
import java.util.List;

@RestController
@RequestMapping("/api/produtos")
public class ProdutoController {

    @Autowired
    private ProdutoService service;

    @GetMapping
    public ResponseEntity<List<ProdutoDTO>> findAll() {
        return ResponseEntity.ok(service.findAll());
    }

    @GetMapping("/{id}")
    public ResponseEntity<ProdutoDTO> findById(@PathVariable Integer id) {
        return ResponseEntity.ok(service.findById(id));
    }

    @PostMapping
    public ResponseEntity<ProdutoDTO> create(@Valid @RequestBody ProdutoFormDTO produtoFormDTO) {
        ProdutoDTO newDto = service.create(produtoFormDTO);
        URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
                .buildAndExpand(newDto.id()).toUri();
        return ResponseEntity.created(uri).body(newDto);
    }

    @PutMapping("/{id}")
    public ResponseEntity<ProdutoDTO> update(@PathVariable Integer id, @Valid @RequestBody ProdutoFormDTO produtoFormDTO) {
        ProdutoDTO updatedDto = service.update(id, produtoFormDTO);
        return ResponseEntity.ok(updatedDto);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable Integer id) {
        service.delete(id);
        return ResponseEntity.noContent().build();
    }
}

Observação Importante: Note que os controllers injetam as interfaces (ProdutoService), não as implementações (ProdutoServiceImpl). Isso é o Princípio da Inversão de Dependência em ação!


Conclusão do Módulo 3 e Próximos Passos

Parabéns! Você acaba de construir uma API REST completa. Neste ponto, temos:

Se você executar a aplicação agora, poderá usar uma ferramenta como Postman, Insomnia ou até mesmo o comando curl para interagir com a sua API. Você pode criar, listar, atualizar e deletar produtos, categorias e fornecedores.

O Grande Problema: Nossa API está totalmente desprotegida. Qualquer pessoa pode deletar todos os produtos!

No próximo módulo, vamos resolver isso. Mergulharemos fundo no Spring Security para “trancar as portas” da nossa API, implementando um sistema de autenticação e autorização robusto e moderno com JSON Web Tokens (JWT).