diff --git a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/controller/MedicoController.java b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/controller/MedicoController.java new file mode 100644 index 0000000..69bb17a --- /dev/null +++ b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/controller/MedicoController.java @@ -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); + } + +} diff --git a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/direccion/DatosDireccion.java b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/direccion/DatosDireccion.java new file mode 100644 index 0000000..892015c --- /dev/null +++ b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/direccion/DatosDireccion.java @@ -0,0 +1,4 @@ +package med.voll.api.direccion; + +public record DatosDireccion(String calle, String distrito, String cuidad, String numero, String complemento) { +} diff --git a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/DatosRegistroMedico.java b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/DatosRegistroMedico.java new file mode 100644 index 0000000..0c22109 --- /dev/null +++ b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/DatosRegistroMedico.java @@ -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) { + +} diff --git a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/Especialidad.java b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/Especialidad.java new file mode 100644 index 0000000..752c4b6 --- /dev/null +++ b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/Especialidad.java @@ -0,0 +1,8 @@ +package med.voll.api.medico; + +public enum Especialidad { + ORTOPEDIA, + CARDIOLOGIA, + GINECOLOGIA, + PEDIATRIA +} diff --git a/010_spring_boot/imgs/spring_boot_cors_error.png b/010_spring_boot/imgs/spring_boot_cors_error.png new file mode 100644 index 0000000..4d9a5fa Binary files /dev/null and b/010_spring_boot/imgs/spring_boot_cors_error.png differ diff --git a/010_spring_boot/spring_boot_1.md b/010_spring_boot/spring_boot_1.md index e9c3446..3c5c9e0 100644 --- a/010_spring_boot/spring_boot_1.md +++ b/010_spring_boot/spring_boot_1.md @@ -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 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 nuevas características principales son: @@ -110,3 +109,221 @@ api └── 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 + + Mochila + 89.90 + Mochila para notebooks de hasta 17 pulgadas + +``` + +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,
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) + diff --git a/README.md b/README.md index 654f977..90c7c4f 100644 --- a/README.md +++ b/README.md @@ -50,3 +50,4 @@ primoridiales en programación con Javascript - [JDBC](./010_spring_boot/jdbc.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) + - [Desarrollo API Rest](./010_spring_boot/spring_boot_1.md)