Desarrollo API Rest: Aula 2

- mapeo de solicitudes POST en clase Controller
- solicitudes POST a la API usando Insomnia
- datos a la API en formato JSON
- anotación @RequestBody para recibir datos del
cuerpo de la solicitud en un parámetro en el
Controller
- patrón DTO con Java Records, representando datos
recibidos en un POST.
This commit is contained in:
devfzn 2023-09-08 16:28:22 -03:00
parent d4e5da3592
commit 41f062fdd7
Signed by: devfzn
GPG Key ID: E070ECF4A754FDB1
7 changed files with 254 additions and 1 deletions

View File

@ -0,0 +1,15 @@
package med.voll.api.controller;
import med.voll.api.medico.DatosRegistroMedico;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/medicos")
public class MedicoController {
@PostMapping
public void registrarMedico(@RequestBody DatosRegistroMedico datosRegistroMedico) {
System.out.println(datosRegistroMedico);
}
}

View File

@ -0,0 +1,4 @@
package med.voll.api.direccion;
public record DatosDireccion(String calle, String distrito, String cuidad, String numero, String complemento) {
}

View File

@ -0,0 +1,8 @@
package med.voll.api.medico;
import med.voll.api.direccion.DatosDireccion;
public record DatosRegistroMedico(String nombre, String email, String documento,
Especialidad especialidad, DatosDireccion direccion) {
}

View File

@ -0,0 +1,8 @@
package med.voll.api.medico;
public enum Especialidad {
ORTOPEDIA,
CARDIOLOGIA,
GINECOLOGIA,
PEDIATRIA
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -66,7 +66,6 @@ El lanzamiento de Spring Boot fue un hito para el desarrollo de aplicaciones
Java, ya que hizo más simple y ágil esta tarea, facilitando mucho la vida de Java, ya que hizo más simple y ágil esta tarea, facilitando mucho la vida de
las personas que utilizan el lenguaje Java para desarrollar sus aplicaciones. las personas que utilizan el lenguaje Java para desarrollar sus aplicaciones.
La versión 3 de Spring Boot se lanzó en noviembre de 2022 y algunas de sus La versión 3 de Spring Boot se lanzó en noviembre de 2022 y algunas de sus
nuevas características principales son: nuevas características principales son:
@ -110,3 +109,221 @@ api
└── pom.xml └── pom.xml
``` ```
### Utilizando Insomnia
AppImage de [Insomnia](https://github.com/Kong/insomnia/releases/) para probar API
Test post a `http://127.0.0.1:8080/medicos`, **json**
```json
{
"nombre": "Rodrigo Lopez",
"email": "rodrigo.lopez@voll.med",
"documento": "123456",
"especialidad": "ortopedia",
"direccion": {
"calle": "calle 1",
"distrito": "distrito 1",
"ciudad": "Lima",
"numero": "1",
"complemento": "a"
}
}
```
#### JSON
**JSON** (JavaScript Object Notation) es un formato utilizado para representar
información, al igual que **XML** y **CSV**.
Una API necesita recibir y devolver información en algún formato que represente
los recursos que administra. **JSON** es uno de estos posibles formatos, popular
por su ligereza, sencillez, facil lectura (humana y máquina), así como por su
soporte para diferentes lenguajes de programación.
Representación de información en formato **XML**
```xml
<producto>
<nombre>Mochila</nombre>
<precio>89.90</precio>
<descripcion>Mochila para notebooks de hasta 17 pulgadas</descripcion>
</producto>
```
Representación en formato **JSON**
```json
{
“nombre” : “Mochila”,
“precio” : 89.90,
“descripcion” : “Mochila para notebooks de hasta 17 pulgadas”
}
```
Observe cómo el formato JSON es mucho más compacto y legible. Precisamente por eso, se ha convertido en el formato universal utilizado en la comunicación de aplicaciones, especialmente en el caso de las API REST.
Más detalles sobre [JSON](https://www.json.org/json-es.html)
#### CORS
Al desarrollar una API y se busca que sus recursos estén disponibles para
cualquier ***cliente HTTP***.
**CORS** (Cross-Origin Resource Sharing) o “Intercambio de recursos con
diferentes orígenes”. Es común tener errores CORS al consumir y poner a
disposición una API.
![img](./imgs/spring_boot_cors_error.png)
**CORS** es un mecanismo utilizado para agregar encabezados HTTP que indica a
los navegadores permitir que una aplicación web se ejecute en un origen y acceda
a los recursos desde un origen diferente. Este tipo de acción se denomina
***cross-origin HTTP request***.
En la práctica, les informa a los navegadores si se puede acceder o no a un
recurso en particular.
Entendiendo los errores
***`Same-origin policy`***
Por defecto, una aplicación Front-end, escrita en JavaScript, solo puede acceder
a los recursos ubicados en el mismo origen de la solicitud. Esto sucede debido
a la política del mismo origen (*same-origin policy*), que es un mecanismo de
seguridad de los navegadores que restringe la forma en que un documento o script
de un origen interactúa con los recursos de otro.
Esta política tiene como objetivo detener los ataques maliciosos.
Dos URL comparten el mismo origen si el **protocolo**, el **puerto** (si se
especifica) y el **host** son los mismos. Comparemos posibles variaciones
considerando la URL `https://cursos.alura.com.br/category/programacao`:
| URL | Resultado | Motivo |
| - | - | - |
| `https://cursos.alura.com.br/category/front-end` | Mismo origen | Solo camino diferente |
| `http://cursos.alura.com.br/category/programacao` |Error de CORS | Protocolo diferente (http) |
| `https://faculdade.alura.com.br:80/category/programacao` | Error de CORS | Host diferente |
#### ¿Como consumir una API con una URL diferente sin tener problemas CORS?
Por ejemplo, si se quiere consumir una API que se ejecuta en el puerto `8000` desde
una aplicación React corriendo en el puerto `3000`.
Al enviar una solicitud a una API de origen diferente, la API debe devolver un
header llamado `Access-Control-Allow-Origin`. Dentro de esta, es ella es necesario
informar los diferentes orígenes que serán permitidas de consumir la API, en
este caso: `Access-Control-Allow-Origin: http://localhost:3000`.
Para permitir el acceso desde cualquier origen se utiliza el símbolo `*`:
`Access-Control-Allow-Origin: *`. Esta es una medida **no recomendada**, ya que
permite que fuentes desconocidas accedan al servidor, a menos que sea intencional,
como en el caso de una API pública.
**¿Cómo hacer esto en Spring Boot correctamente?**
#### Habilitando diferentes orígenes en Spring Boot
Configurar el **CORS** para permitir que un origen específico consuma la API,
creando una clase de configuración como la sgte.
```java
@Configuration
public class CorsConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE",
"OPTIONS", "HEAD", "TRACE", "CONNECT");
}
}
```
`http://localhost:3000` sería la dirección de la aplicación Front-end y
`.allowedMethods` los métodos que se permitirán ejecutar. Con esto se podrá
consumir la API sin problemas desde una aplicación front-end.
#### Restricciones o validaciones
|| Médico ||
| :- | :- | :- |
| Nombre | Solo letras | No puede llegar vacío |
| Especialidad | Ortopedia, Ginecología,<br>Cardiología, Pediatria | No puede llegar vacío |
| Documento | Solo números | No puede llegar vacío |
| Email | Formato de email | No puede llegar vacío |
| Teléfono | Solo números | No puede llegar vacío |
|| Dirección ||
| :- | :- | :- |
| Calle | Letras y números | No puede llegar vacío |
| Número | Solo números | No puede llegar vacío |
| Complemento | Letras y números | |
| Cuidad | Letras y números | No puede llegar vacío |
### Java Record
Lanzado oficialmente en Java 16, pero disponible experimentalmente desde Java 14.
**Record** es un recurso que ***permite representar una clase inmutable, que
contiene solo atributos, constructor y métodos de lectura***, de una manera muy
simple y ágil.
Este tipo de clase encaja perfectamente para representar **clases DTO**, ya que
su objetivo es únicamente representar datos que serán recibidos o devueltos por
la API, sin ningún tipo de comportamiento.
Para crear una clase DTO inmutable, sin la utilización de Record, era necesario
escribir mucho código. El sgte. es un ejemplo de una clase DTO que representa
un teléfono:
```java
public final class Telefono {
private final String ddd;
private final String numero;
public Telefono(String ddd, String numero) {
this.ddd = ddd;
this.numero = numero;
}
@Override
public int hashCode() {
return Objects.hash(ddd, numero);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (!(obj instanceof Telefono)) {
return false;
} else {
Telefono other = (Telefono) obj;
return Objects.equals(ddd, other.ddd)
&& Objects.equals(numero, other.numero);
}
}
public String getDdd() {
return this.ddd;
}
public String getNumero() {
return this.numero;
}
}
```
Con **Record** todo ese código se puede resumir en una sola línea:
```java
public record Telefono(String ddd, String numero){}
```
Internamente, Java transforma este registro en una clase inmutable, muy similar
al código que se muestra arriba.
Documentación Java
[record](https://docs.oracle.com/en/java/javase/17/language/records.html)

View File

@ -50,3 +50,4 @@ primoridiales en programación con Javascript
- [JDBC](./010_spring_boot/jdbc.md) - [JDBC](./010_spring_boot/jdbc.md)
- [Persistencia con JPA - Hibernate](./010_spring_boot/jpa_persistencia_hibernate.md) - [Persistencia con JPA - Hibernate](./010_spring_boot/jpa_persistencia_hibernate.md)
- [JPA consultas avanzadas, rendimiento y modelos complejos](./010_spring_boot/jpa_avanzado.md) - [JPA consultas avanzadas, rendimiento y modelos complejos](./010_spring_boot/jpa_avanzado.md)
- [Desarrollo API Rest](./010_spring_boot/spring_boot_1.md)