Skip to content

API RESTful

Jalussa dos Santos edited this page Feb 27, 2024 · 51 revisions

Configurações iniciais

Spring Initializr

  • O Spring Initializr, acessado pelo site https://start.spring.io/, é o primeiro passo para criar o projeto. Essa ferramenta serve para criar o projeto com toda estrutura inicial necessária.

  • É possível incluir as configurações necessárias para iniciar, como por exemplo:

  1. Linguagem de programação: Java 17
  2. Módulo de configurações do Spring: Spring Boot 3.3.0
  3. Gestão de dependências e de build: Gradle
  • Dependências:
  1. Spring Boot DevTools: módulo do Spring Boot que serve para não precisarmos reiniciar a aplicação a cada alteração feita no código. Isto é, toda vez que salvarmos as modificações feitas no código, ele subirá automaticamente.
  2. Lombok: ferramenta para gerar códigos, como esses códigos verbosos do Java, de getter e setter, baseado em anotações. Usaremos o Lombok para deixarmos o código mais simples e menos verboso.
  3. Spring Web: Módulo do Spring para desenvolvimento de aplicações Web e API's Rest

Reiniciando a aplicação automaticamente

  • Com o Spring Boot DevTools, ao salvar uma mudança no código o projeto se reunicia automaticamente, mas para isso é necessário configurar o devtools na IDE:
  1. File > Settings > Build, Execution, Deployment > Compiler: Marcar a opção Build project automatically
  2. File > Settings > Advanced Settings: Marcar a opção Allow auto-make to start even if developed application is currently running

Executando e subindo a aplicação localmente

  • Na packge main, existe uma classe application para dar o start da aplicação. Em projetos tradicionais precisamos de um servidor de aplicação (TomCat, Jetty, Glassfish e Weblogic), e colocávamos o projeto dentro do servidor e o inicializavámos. Dessa forma, ele fazia toda configuração e disponibilizava a aplicação. No Spring Boot, por padrão, o projeto vem com o TomCat como servidor de aplicação e ele já está embutido dentro das dependências do módulo web. Ele não aparece no arquivo de dependências porque está no xml do Spring Boot herdado.

  • A classe application, possui uma anotação @SpringBootApplication, com um método main. Este chama um método estático denominado run de uma classe do Spring nomeada SpringApplication. Portanto, para rodar o projeto, basta rodar essa classe com o método main, que estamos chamando essa classe do Spring SpringApplication com o método run. É este método que inicializa o projeto.

  • Para acessar a aplicação, basta acessar a URL localhost:8080

Configurações do banco de dados

Instalação do MYSQL

Arquivos properties x Arquivos YAML

  • Por padrão, o Spring Boot acessa as configurações definidas no arquivo application.properties, que usa um formato de chave=valor. Cada linha é uma configuração única, então é preciso expressar dados hierárquicos usando os mesmos prefixos para nossas chaves, ou seja, precisamos repetir prefixos, neste caso, spring e datasource, como por exemplo:

image

  • YAML é um outro formato bastante utilizado para definir dados de configuração hierárquica, como é feito no Spring Boot. A configuração se tornou mais legível, pois não contém prefixos repetidos, como por exemplo:

image

Flyway - Migration SQL

  • O Flyway é uma ferramenta de migração suportada pelo Spring Boot. Ele permite controlar e modificar tabelas do banco de dados de forma automatizada. Na aula, aprendemos a utilizar o Flyway para criar um diretório específico para armazenar os arquivos SQL de migração e criamos o primeiro arquivo SQL para criar a tabela de médicos.

  • Para cada mudança que quisermos executar no banco de dados, precisamos criar um arquivo .sql no projeto e, nele, escrever o trecho do comando SQL que será executado no banco de dados. Precisamos salvá-los em um diretório específico: "db > migration", com o nome, conforme exemplo: "V1__create-table-medicos.sql". A cada mudança na estrutura de dados deve ser criado um novo arquivo sql com as alterações pertinentes.

  • Em casos de erro na migration: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Validate failed: Migrations have failed validation Para resolver esse problema será necessário acessar o banco de dados da aplicação e executar o seguinte comando sql: delete from flyway_schema_history where success = 0;

  • Pode acontecer de alguma migration ter criado uma tabela e/ou colunas e com isso o problema vai persistir, pois o flyway não vai apagar as tabelas/colunas criadas em migrations que falharam. Nesse caso você pode apagar o banco de dados e criá-lo novamente: drop database nome_data_base; create database nome_data_base;

SPRING - Anotações para requisições

Controller

  • Controller é uma classe responsável por receber as requisições HTTP e direcioná-las para as ações corretas dentro de uma aplicação. No contexto do curso, o controller é responsável por receber as requisições relacionadas aos médicos e executar as ações correspondentes, como cadastrar um novo médico. Ele utiliza anotações, como @RestController e @RequestMapping, para mapear as URLs e definir os métodos que serão executados para cada tipo de requisição.

@RestController

  • A anotação @RestController é essencial para que o Spring Boot reconheça a classe como um controlador REST, o que permite que as requisições HTTP sejam devidamente mapeadas para os métodos dentro da classe. Sem essa anotação, o Spring não consegue expor os endpoints da API, o que pode levar ao erro 404 - Not Found ao tentar acessar o recurso. Continue assim, prestando atenção aos detalhes das anotações e ao funcionamento do Spring Boot.

@RequestMapping

  • A anotação @RequestMapping é usada para mapear uma requisição HTTP para um método específico em um controller. No contexto do projeto, a classe HelloController possui a anotação @RequestMapping("/medicos"), o que significa que todos os métodos dentro dessa classe serão mapeados para a URL /medicos. Portanto, quando você acessar localhost:8080/medicos no navegador, o método correspondente será executado e a mensagem "Hello World!" será exibida.

@PostMapping

  • A anotação @PostMapping é utilizada em um método de um controller para indicar que ele deve ser executado quando uma requisição do tipo POST é feita para a URL mapeada pelo controller. Essa anotação é uma abreviação das anotações @RequestMapping com o método HTTP POST. Ao utilizar @PostMapping, não é necessário especificar o método HTTP na anotação, tornando o código mais legível e conciso. No contexto do curso, o método cadastrar() do MedicoController utiliza a anotação @PostMapping para lidar com as requisições POST para a URL "/medicos".

@RequestBody

  • A anotação @RequestBody serve para receber os dados enviados no controller. Sem essa anotação o Spring não vai ler o corpo da requisição e mapear os campos dele para o DTO recebido como parâmetro.

@GetMapping

  • A anotação @GetMapping é usada para mapear uma requisição HTTP GET para um método específico em um controller. No contexto do projeto, o método olaMundo() na classe HelloController possui a anotação @GetMapping e é mapeado para a URL /medicos. Quando você acessar localhost:8080/medicos no navegador, a mensagem "Hello World!" será exibida.

@PutMapping

  • O @PutMapping é uma anotação utilizada no Spring Boot para mapear uma requisição HTTP do tipo PUT para um método específico em um controller. Nesse caso, o método atualizar está sendo mapeado para receber uma requisição PUT. O método PUT substitui todos os atuais dados de um recurso pelos dados passados na requisição, ou seja, estamos falando de uma atualização integral. Então, com ele, fazemos a atualização total de um recurso em apenas uma requisição.

@PatchMapping

  • O método PATCH, por sua vez, aplica modificações parciais em um recurso. Logo, é possível modificar apenas uma parte de um recurso. Com o PATCH, então, realizamos atualizações parciais, o que torna as opções de atualização mais flexíveis.

@DeleteMapping

  • É utilizada para mapear uma requisição DELETE em um método específico de um controller no Spring Boot. Ela permite que você defina a URL e os parâmetros necessários para a exclusão de um recurso.

@PathVariable

  • É utilizada para mapear um parâmetro de uma URL para um parâmetro de um método em um controller no Spring Boot. Ela permite que você obtenha o valor de um parâmetro dinâmico presente na URL da requisição. No contexto da aula, foi utilizado o "@PathVariable" para obter o ID do médico a ser excluído.

SPRING - Anotações para configurações

@Configuration

  • A anotação @Configuration é usada em classes do Spring para indicar que essa classe é responsável por definir as configurações do aplicativo. Essas configurações podem incluir a definição de beans, configurações de segurança, configurações de banco de dados, entre outras. Ao marcar uma classe com @Configuration, o Spring irá reconhecê-la e aplicar as configurações definidas nessa classe durante a inicialização do aplicativo.

@Autowired

  • @Autowired é uma anotação do Spring Framework que é usada para realizar a injeção de dependência em uma classe. Quando você usa a anotação @Autowired em um campo, método setter ou construtor, o Spring irá procurar uma instância do tipo correspondente e injetá-la automaticamente. No contexto do Spring Boot e do Spring Data JPA, a anotação @Autowired é frequentemente usada para injetar dependências de repositórios em classes de serviço ou controladores. Por exemplo, ao usar a anotação @Autowired em um campo do tipo MedicoRepository em uma classe de serviço, o Spring irá procurar uma instância de MedicoRepository e injetá-la automaticamente na classe de serviço. Essa injeção de dependência facilita a utilização de classes e componentes em conjunto, tornando o código mais modular, testável e de fácil manutenção.

@Transactional

  • A anotação @Transactional é utilizada no método "cadastrar" do controlador MedicoController para indicar que a operação de salvar um novo médico no banco de dados deve ser realizada dentro de uma transação. Isso garante que, caso ocorra algum erro durante o processo, a transação será revertida e as alterações não serão persistidas no banco de dados.

JAVA - Funções

Record

  • Lançado oficialmente no Java 16, mas disponível desde o Java 14 de maneira experimental, em Java, a palavra-chave "record" é usada para criar classes imutáveis e concisas para representar dados. Um record é uma classe que possui campos, construtor, métodos de acesso (getters) e métodos equals(), hashCode() e toString() automaticamente gerados pelo compilador. Essa sintaxe simplificada permite criar classes de dados de forma mais rápida e legível, sem a necessidade de escrever código repetitivo. Os records são úteis quando se deseja criar objetos simples para armazenar dados, como DTOs (Data Transfer Objects) ou classes de modelo.

SPRING- Anotações JPA

@Table

  • A anotação "@Table" é utilizada para mapear uma classe como uma entidade de banco de dados. Ela é usada para definir o nome da tabela que será criada no banco de dados para armazenar os objetos dessa classe.

@Entity

  • A anotação "@Entity" é utilizada para mapear uma classe como uma entidade de banco de dados. Ela indica que a classe representa uma tabela no banco de dados e que os objetos dessa classe serão persistidos nessa tabela.

@Id

  • A anotação "@Id" é utilizada para indicar que um atributo da classe é a chave primária da entidade no banco de dados. Ela é usada para identificar de forma única cada registro na tabela.

@GeneratedValue

  • A anotação "@GeneratedValue" é utilizada em conjunto com a anotação "@Id" para indicar que o valor da chave primária será gerado automaticamente pelo banco de dados. Ela é usada para definir a estratégia de geração do valor da chave primária, como por exemplo, auto incremento. Isso evita que o desenvolvedor precise atribuir manualmente um valor para a chave primária ao inserir um novo registro no banco de dados.

@Enumerated

  • A anotação "@Enumerated" é utilizada para mapear um atributo de uma entidade que representa uma enumeração no banco de dados. Ela é usada para definir como o valor da enumeração será persistido no banco de dados, podendo ser como uma string (EnumType.STRING) ou como um número (EnumType.ORDINAL). Isso permite que a enumeração seja armazenada de forma adequada no banco de dados.

@Embedded

  • A anotação "@Embedded" é utilizada para indicar que uma classe é embutida em outra classe como um atributo. Ela é usada para definir que os atributos da classe embutida serão mapeados como colunas na tabela da classe que a contém. Isso permite que a classe embutida seja tratada como parte da entidade principal no banco de dados.

@Embeddable

  • A anotação "@Embeddable" é utilizada para indicar que uma classe pode ser embutida em outra classe como um atributo. Ela é usada para definir que os atributos da classe anotada serão mapeados como colunas na tabela da classe que a contém. Isso permite que a classe anotada seja tratada como parte da entidade principal no banco de dados.

JPA Repository X DAO

  • As interfaces Repository são uma parte importante do Spring Data JPA. Elas fornecem métodos para manipulação de dados no banco de dados, como inserção, atualização, exclusão e consulta. No exemplo dado, a interface MedicoRepository herda da interface JpaRepository, que já possui implementações padrão para esses métodos. Isso nos permite utilizar esses métodos sem precisar escrever o código manualmente. Entre <> da interface, passaremos dois tipos de objeto: O primeiro será o tipo da entidade trabalhada pelo repository, Medico, e o tipo do atributo da chave primária da entidade, Long.

  • A interface JpaRepository é uma interface fornecida pelo Spring Data JPA que estende a interface PagingAndSortingRepository. Ela fornece métodos para realizar operações de CRUD (Create, Read, Update, Delete) no banco de dados de forma simples e eficiente. Além disso, a JpaRepository também oferece métodos para realizar consultas personalizadas utilizando o mecanismo de criação de consultas do Spring Data JPA. É uma ótima opção para simplificar o acesso e manipulação de dados em uma aplicação Spring Boot.

  • DAO (Data Access Object) é um padrão de projeto que tem como objetivo separar a lógica de acesso a dados da lógica de negócio em uma aplicação. Ele fornece uma interface entre a camada de negócio e a camada de persistência, permitindo que as operações de acesso a dados sejam realizadas de forma independente do banco de dados utilizado.

  • No contexto do Spring Data JPA, as interfaces Repository podem ser consideradas como implementações do padrão DAO. Elas encapsulam a lógica de acesso a dados e fornecem métodos para realizar operações de CRUD no banco de dados.

JPA Repository - save

  • O método repository.save() é utilizado para salvar um objeto no banco de dados. Ele recebe como parâmetro o objeto que você deseja salvar e retorna o objeto salvo com o ID gerado pelo banco de dados. Por exemplo: repository.save(medico); Nesse exemplo, um objeto Medico é criado e preenchido com informações. Em seguida, o método save() é chamado passando o objeto medico como parâmetro. Isso irá salvar o objeto no banco de dados.

JPA Repository - findAll

  • O método "findAll" é utilizado para buscar todos os registros de uma entidade no banco de dados. Ele é comumente utilizado em operações de listagem.

Entidades JPA x DTOs

  • Em resumo, as entidades JPA representam a estrutura do banco de dados, enquanto as DTOs representam os dados que serão transferidos pela API.

  • As entidades JPA são classes que representam as tabelas do banco de dados e são mapeadas utilizando a JPA. Elas possuem anotações que definem as colunas da tabela, os relacionamentos com outras entidades, entre outras configurações.

  • Os DTOs são classes que servem como objetos de transferência de dados entre a API e o cliente. Elas são utilizadas para encapsular os dados que serão enviados ou recebidos pela API, permitindo um controle mais preciso sobre quais informações serão expostas e evitando o vazamento de dados sensíveis.

Mass Assignment X Entidades x DTOs

  • Um ataque de Mass Assignment ocorre quando um invasor tenta manipular os dados de um objeto, atribuindo valores a propriedades que não deveriam ser acessíveis ou modificáveis. No contexto da aula, o uso do DTO DadosAtualizacaoMedico ajuda a prevenir esse tipo de ataque, pois apenas os campos permitidos para atualização são enviados na requisição PUT. Além disso, o método atualizarInformacoes() no controller e na classe Endereco garantem que apenas os campos preenchidos sejam atualizados. Dessa forma, é possível evitar que dados indesejados sejam modificados por um atacante.

Pageable

  • O Pageable é um parâmetro que permite configurar a paginação e ordenação em uma requisição para a API. Utilizando o Pageable, podemos controlar o número de registros exibidos por página e a página a ser exibida.

  • O parâmetro "size" é utilizado na URL para controlar o número de registros exibidos por página. Por exemplo, se você utilizar o parâmetro "size=10", a API irá retornar apenas 10 registros por página. Se não passarmos o parâmetro size, o Spring devolverá 20 registros por padrão.

  • O parâmetro "page" é utilizado na URL para controlar a página a ser exibida. Por exemplo, se você utilizar o parâmetro "page=2", a API irá retornar a segunda página de resultados. Ex.: http://localhost:8080/medicos?size=1&page=1

Ordenação

  • Para mudar a ordenação, é utilizado o parâmetro na URL, chamado sort. Junto dele, passamos o nome do atributo na entidade. Se quisermos ordenar pelo nome, por exemplo, passaremos a URL http://localhost:8080/medicos?sort=nome. Por padrão, a ordenação acontece de maneira crescente, mas é possível ordenar por ordem decrescente. Para isso, basta adicionar ,desc à URL. É possível combinar com os parâmetro que vimos no vídeo anterior. Basta adicioná-los na URL, sempre conectando-os com um &, como no exemplo: http://localhost8080/medicos?sort=crm,desc&size=2&page=1

  • O padrão é 20 resultados por página, e na ordem em que foi cadastrada a informação no banco de dados. Para alterar esse padrão, podemos trocar o padrão da paginação adicionando uma anotação no parâmetro Pageable. O nome dela é @PageableDefault. Na sequência, abrimos parênteses e passamos os atributos size, page e sort. Podemos escolher o atributo que guiará a ordenação, passando entre chaves duplas. Por exemplo, se passarmos lista(@PageableDefault(size = 10, sort = {"nome"}), isso significa que, caso não passemos parâmetros na URL ao fazer o GET, o novo padrão será a exibição de 10 resultados por página, ordenados a partir do nome.

Page

  • O Page é o tipo de retorno utilizado quando queremos retornar uma página de resultados ao invés de uma lista completa. O JSON devolvido, terá o atributo content, com o array da lista dentro dele. Ao final do objeto de retorno, encontraremos informações relacionadas à paginação.

Logar o SQL executado

  • Para saber como a query está sendo feita no banco de dados, podemos configurar os properties para que isso seja exibido. A configuração é feita em "src > main > resources > application.properties". Adicionando spring.jpa.show-sql=true, os SQLs disparados no banco de dados serão impressos e exibidos numa linha só. Para facilitar a visualização, pode ser configurado o parâmetro, que passa as informações com quebras de linha no aplication.properties", com a propriedade spring.jpa.properties.hibernate.format_sql=true.

Configurando tradução dos parâmetros de paginação

  • Os parâmetros utilizados para realizar a paginação e a ordenação devem se chamar page, size e sort. Entretanto, o Spring Boot permite que os nomes de tais parâmetros sejam modificados via configuração no arquivo application.properties, conforme:

spring.data.web.pageable.page-parameter=pagina

spring.data.web.pageable.size-parameter=tamanho

spring.data.web.sort.sort-parameter=ordem

  • Nas requisições que utilizam paginação, devemos utilizar esses nomes que foram definidos. Por exemplo, para listar os médicos de nossa API trazendo apenas 5 registros da página 2, ordenados pelo e-mail e de maneira decrescente, a URL da requisição deve ser: http://localhost:8080/medicos?tamanho=5&pagina=1&ordem=email,desc.

JPA Repository - getReferenceById

  • É utilizado para obter uma referência a um objeto do tipo "Medico" com base no seu ID. Ele é utilizado no método "excluir" da classe "MedicoController" para obter a referência do médico que será excluído.

JPA Repository - deleteById

  • É utilizado para excluir um objeto do tipo "Medico" com base no seu ID. No código fornecido, o método "excluir" da classe "MedicoController" utiliza esse método para excluir o médico marcando-o como inativo, definindo o atributo "ativo" como false. Dessa forma, o médico não é removido do banco de dados, mas sim marcado como inativo.

Copiar texto da Luri para área de transferêcia

LOMBOK - Anotações

@Getter

  • A anotação "@Getter" é utilizada para gerar automaticamente os métodos getters para os atributos de uma classe. Ela é usada para acessar os valores dos atributos de forma mais conveniente, sem a necessidade de escrever manualmente os métodos getters para cada atributo. Isso torna o código mais conciso e legível.

@NoArgsConstructor

  • A anotação "@NoArgsConstructor" é utilizada para gerar automaticamente um construtor sem parâmetros para uma classe. Ela é usada para facilitar a criação de objetos dessa classe sem a necessidade de passar argumentos para o construtor. Isso é útil em situações em que desejamos criar objetos vazios ou preencher os atributos posteriormente.

@AllArgsConstructor

  • A anotação "@AllArgsConstructor" é utilizada para gerar automaticamente um construtor que recebe como parâmetros todos os atributos da classe. Ela é usada para facilitar a criação de objetos dessa classe, evitando a necessidade de escrever manualmente um construtor com todos os atributos como parâmetros. Isso torna o código mais conciso e legível.

@EqualsAndHashCode

  • A anotação "@EqualsAndHashCode" é utilizada para gerar automaticamente os métodos equals() e hashCode() para uma classe. Ela é usada para comparar objetos dessa classe com base em seus atributos e calcular um código hash único para cada objeto. Isso facilita a comparação e o uso de objetos dessa classe em estruturas de dados como conjuntos (Set) e mapas (Map).

SPRING - Anotações Bean validation

  • As anotações mencionadas (@Valid, @Email, @NotBlank, @NotNull, @Pattern) são utilizadas para realizar validações nos campos do DTO CadastroMedico e Endereco. Você pode conferir uma lista com as principais anotações do Bean Validation na documentação oficial da especificação.

@Valid

  • O @Valid é responsável por integrar o Spring ao Bean Validation e executar as validações.

@Email

  • O @Email verifica se o campo é um endereço de email válido.

@NotBlank

  • O @NotBlank verifica se o campo não está vazio ou contém apenas espaços em branco.

@NotNull

  • O @NotNull verifica se o campo não é nulo.

@Pattern

  • @Pattern verifica se o campo atende a um padrão específico, definido por uma expressão regular.

Jackson- Anotações

@JsonIgnore

  • É utilizada para indicar que um determinado atributo de uma classe deve ser ignorado durante a serialização ou desserialização de objetos JSON.

  • Quando um objeto é convertido para JSON, por exemplo, para ser enviado como resposta em uma requisição, a anotação @JsonIgnore faz com que o atributo marcado seja excluído do JSON resultante. Isso pode ser útil quando se deseja ocultar informações sensíveis ou evitar a exposição de dados desnecessários.

  • Pode acontecer de existir algum outro endpoint da API na qual precisamos enviar no JSON o salário dos funcionários, sendo que nesse caso teríamos problemas, pois com a anotação @JsonIgnore tal atributo nunca será enviado no JSON, e ao remover a anotação o atributo sempre será enviado. Perdemos, com isso, a flexibilidade de controlar quando determinados atributos devem ser enviados no JSON e quando não.

Loop infinito causando StackOverflowError

  • Outro problema muito recorrente ao se trabalhar diretamente com entidades JPA acontece quando uma entidade possui algum autorrelacionamento ou relacionamento bidirecional.

  • Ao retornar um objeto do tipo Produto no Controller, o Spring teria problemas para gerar o JSON desse objeto, causando uma exception do tipo StackOverflowError. Esse problema ocorre porque o objeto produto tem um atributo do tipo Categoria, que por sua vez tem um atributo do tipo List, causando assim um loop infinito no processo de serialização para JSON. Tal problema pode ser resolvido com a utilização da anotação @JsonIgnore ou com a utilização das anotações @JsonBackReference e @JsonManagedReference, mas também poderia ser evitado com a utilização de um DTO que representa apenas os dados que devem ser devolvidos no JSON.

@JsonBackReference e @JsonManagedReference

  • É utilizada em relacionamentos bidirecionais entre entidades JPA para evitar a recursão infinita durante a serialização de objetos JSON. Para resolver esse problema, podemos utilizar a anotação @JsonBackReference em um dos lados do relacionamento, no caso no atributo do tipo categoria da classe produto. Essa anotação indica que o lado anotado será ignorado durante a serialização, evitando assim o loop infinito.

  • É importante ressaltar que a anotação @JsonBackReference deve ser utilizada apenas em um dos lados do relacionamento, enquanto o outro lado deve utilizar a anotação @JsonManagedReference para indicar que é o lado "gerenciado" do relacionamento, no caso no atributo do tipo List da classe categoria.

Utilitários para requisições

JSON (JavaScript Object Notation)

  • JSON é um formato utilizado para representação de informações, assim como XML e CSV. Uma API precisa receber e devolver informações em algum formato, que representa os recursos gerenciados por ela. O JSON é um desses formatos possíveis, tendo se popularizado devido a sua leveza, simplicidade, facilidade de leitura por pessoas e máquinas, bem como seu suporte pelas diversas linguagens de programação. Mais detalhes sobre o JSON podem ser encontrados no site JSON.org.

DTO (Data Transfer Object)

  • O DTO serve para representar os dados de entrada e saída na API. O DTO é uma prática comum para separar a camada de apresentação ao cliente da camada de negócio, permitindo definir quais dados serão expostos. Sempre que precisarmos receber ou devolver dados da API, criaremos um DTO - sendo uma classe ou record que contém apenas os campos que desejamos receber ou devolver da API

CORS (Cross-Origin Resource Sharing) e Same-origin policy

  • O CORS, em português, “compartilhamento de recursos com origens diferentes”. É um mecanismo utilizado para adicionar cabeçalhos HTTP que informam aos navegadores para permitir que uma aplicação Web seja executada em uma origem e acesse recursos de outra origem diferente. Esse tipo de ação é chamada de requisição cross-origin HTTP. Na prática, então, ele informa aos navegadores se um determinado recurso pode ou não ser acessado.

  • Por padrão, uma aplicação Front-end, escrita em JavaScript, só consegue acessar recursos localizados na mesma origem da solicitação. Isso acontece por conta da política de mesma origem (same-origin policy), que é um mecanismo de segurança dos Browsers que restringe a maneira de um documento ou script de uma origem interagir com recursos de outra origem. Essa política possui o objetivo de frear ataques maliciosos.

  • Duas URLs compartilham a mesma origem se o protocolo, porta (caso especificado) e host são os mesmos. Quando queremos consumir uma API que roda na porta 8000 a partir de uma aplicação React rodando na porta 3000, API precisa retornar um header chamado Access-Control-Allow-Origin. Dentro dele, é necessário informar as diferentes origens que serão permitidas para consumir a API, em nosso caso: Access-Control-Allow-Origin: http://localhost:3000.

  • É possível permitir o acesso de qualquer origem utilizando o símbolo *(asterisco): Access-Control-Allow-Origin: *. Mas isso não é uma medida recomendada, pois permite que origens desconhecidas acessem o servidor, a não ser que seja intencional, como no caso de uma API pública

CORS - Habilitando diferentes origens no Spring Boot

  • Para consumir a sua API sem problemas a partir de uma aplicação Front-end, é necessário configurar o CORS e habilitar uma origem específica para consumir a API, basta criar uma classe de configuração implementando WebMvcConfigurer, informando o .allowedOrigins, que seria o endereço da aplicação Front-end e .allowedMethods os métodos que serão permitidos para serem executados.