Mostrando las entradas con la etiqueta Desarrollo web. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Desarrollo web. Mostrar todas las entradas

miércoles, 2 de noviembre de 2022

Creación de una API Rest con Spring Boot (Utilizando MySQL y JPA) - Parte 3: Métodos HTTP e implementación del controlador

Muy buenas a todos, bienvenidos a un nuevo post (vídeo) que va a continuar con la implementación de un CRUD básico, teniendo en cuenta de que se trata de una API Rest como se ha enunciado en los textos (vídeos anteriores); en esta ocasión voy a tocar el tema de los métodos HTTP y del controlador en sí, ya que van de la mano uno tras de otro (valga la redundancia).

Pero bien ... ¿Qué es y cómo se trabaja un controlador en Spring Boot?

"Un controlador es un componente de Spring que es capaz de enviar y recibir peticiones HTTP"

 

Spring Framework for Beginners. En este post se revisan conceptos… | by  sergio arturo espinoza | Alebrije Dev | Medium
Diagrama que relaciona su @Controller con su respectivo @Service y @Repositories

Lo que nos llega a deducir que, un controlador en Spring Boot, no es más que enviar y recibir peticiones, valga la redundancia, cada vez que se haga una nueva solicitud, dichas solicitudes son las que se pueden constatar con los denominados métodos HTTP que se verá a continuación:

  • GET: El método GET tiene como característica, cuándo el usuario manda una petición, para que traiga uno o más datos que están dentro de nuestra base de datos, si no obtendremos nada en concreto; dicha base quedará como un campo vacío.
  • POST: Uno de los métodos más relevantes en los métodos HTTP, este método nos indica que el usuario va a ordenar a nuestra API Rest, que nos guarde dicha información en la base de datos en sí.
  • PUT: Tiene el mismo comportamiento que post, salvo que, sí y solo sí nos permite actualizar la información de un dato existente teniendo en cuenta el tipo de dato, y la llave primaria ID de nuestro dato. 
  • DELETE: Se toma en cuenta el ID de nuestro elemento almacenado, para dar por terminado nuestro respectivo dato.
Después de haber hecho este glosario, podemos definir por medio de las anotacions a que, o quiénes corresponden las anotaciones a los métodos HTTP descritos anteriormente, en todo caso; se mostrará con cada porción de código asociado a cada método en cuestión:
@GetMapping(path = "/all")
La anotación @GetMapping, posee el comportamiento del método GET como se describió anteriormente, nuestra forma de obtener todos los elementos almacenados en nuestra base de datos, a la hora de implementar esta parte del controlador; nuestro código quedará de la siguiente forma, bajo un método que lleva un ResponseEntity,  y su tipo de dato un objeto cualesquiera del tipo T:
 
@GetMapping(path = "/all")
public ResponseEntity<?>getAllUsers()
{
ArrayList<UserModel> allUsers = this.userServiceInterface.getUsers();
boolean checkedUsers = allUsers.isEmpty();

if(checkedUsers==true)
{
System.out.println("The list is empty: ?"+checkedUsers);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Nothing to found here!");
}
else {
System.out.println(checkedUsers);
return ResponseEntity.status(HttpStatus.OK).body(allUsers);
}
}
Cuándo se habla de la anotación @PostMapping, nos dice que el usuario ingresado, será almacenado en nuestra base de datos con base a que, se debe seguir el siguiente código:
@PostMapping(path = "/add")
public ResponseEntity<UserModel> saveUser(@Valid @RequestBody UserModel user)
{
UserModel userSaved = null;
try {
userSaved = this.userServiceInterface.saveUser(user);
}
catch(Exception error)
{
error.getMessage();
}
return new ResponseEntity<>(userSaved,HttpStatus.CREATED);
}
De acuerdo con el método @PutMapping, nos sigue el método un tanto idéntico al @PostMapping para guardar un dato en nuestra base de datos, en sí, lo único que cambia es que dicho método tiene dos parámetros, uno para el usuario, y el otro para el ID o llave primaria de nuestra tabla.
@PutMapping(path = "/add/{id}")
public ResponseEntity<UserModel> upgradeUser(UserModel user,Long id)
{
UserModel userUpgraded = this.userServiceInterface.upgradeUser(user,id);
return ResponseEntity.status(HttpStatus.CREATED).body(userUpgraded);
}
Para borrar un dato en nuestra base de datos, se tendrá en cuenta esta línea de código que se muestra a continuación:
@DeleteMapping(path = "/{id}")
public ResponseEntity<String> deleteById(Long id)
{
boolean ok = this.userServiceInterface.deleteUser(id);
if(ok)
{
return new ResponseEntity<>("The user has been eliminated with the previous id: "+id,HttpStatus.GONE);
}
else{
return new ResponseEntity<>("The user hasn't been eliminated with the previous id: "+id,HttpStatus.BAD_REQUEST);
}
}
En la última entrada, os explicaré cómo funciona el consumo de los servicios de nuestra APIRest como también, los estados HTTP que aún falta por comentar, los ResponseEntity traen como retorno cada estado HTTP que se encuentra previamente configurado.
 
¡Un saludo a todos y hasta la próxima lectura!

martes, 25 de octubre de 2022

Creación de una API Rest con Spring Boot (Utilizando MySQL y JPA) - Parte 2: Implementación del repositorio y del servicio

Hola, muy buenas tardes a todos.

Debido al éxito del vídeo de la primera parte sobre la creación del modelo y de su configuración en el "application.properties"; ahora nos concentraremos en la parte de la constitución de su respectivo repositorio y servicio que son partes esenciales de una API Rest con Spring Boot y JPA, conectando a MySQL.

En todo caso, hoy voy a tratar sobre ¿Qué es un repositorio, y que es un servicio en un API Rest? 

En resumidas cuentas, un repositorio visto desde un archivo en Java no es más que una interfaz que hereda de una serie de "Repositories" y una de ellas en la que vamos a trabajar en este vídeo (artículo) es la de JPA Repository, aunque también podríamos mencionar el CRUDRepository.

Para darle un significado más concreto, un repositorio es una lista de instrucciones por el cual está previamente configurado para que el administrador de sistema, y también, el usuario final, pueda ejecutar las operaciones determinadas, algunas como, buscar por ID, guardar la información en su respectiva bases de datos, o darle al usuario en sí, la facultad de eliminar un dato en la DB.

Generalmente un archivo como el JPARepository es un archivo .class en Java, lo que efectua realmente son las tareas que hace en el CRUD que estamos realizando, y por consiguiente, dichas tareas son agrupadas como métodos con y sin parámetros, la estructura del JPARepository viene a asemejarse a una interfaz, que no es más que, un conjunto de métodos o firmas que llevan o no parámentros.

La sintáxis de nuestro UserRepository, queda expreso de la siguiente forma, aunque también podemos incluir en dicho repositorio, los métodos o firmas definidos por el usuario:

@Repository
public interface UserRepository extends JpaRepository<UserModel,Long>
{

Como puede saber, el archivo UserRepository (repositorio), reune todos los métodos que HEREDAN de la clase JPARepository, llevando consigo dos parámetros encerrados en dos símbolos menor y mayor que, dichos parámetros son determinados como: 1. El tipo de Model (que aparece como UserModel), y 2. El tipo de dato al cuál está asociado la llave primaria ID del archivo UserModel que en este caso es Long.

Como regla general, todo archivo que esté relacionado con el repositorio, se emplea la anotación @Repository.

En resumen, un repositorio no es más que, una colección de métodos heredados de una clase en específico (en este segundo vídeo empleamos el JPARepository) que llevan dos parámetros dados, uno para el tipo de Modelo, y el otro para el tipo de dato que es la llave primaria perteneciente al Modelo perse.

Ahora pasemos de una vez a lo que es un Servicio en una APIRest con Spring Boot, podría deducir que, un servicio no es más que la inyección de los métodos dados en la interfaz UserRepository (más exactamente del repositorio de nuestra APIRest), salvo que, para que se pueda implementar nuestro Servicio a partir de lo anterior, se emplea la anotación @Autowired.

La anotación @Autowired es súper importante utilizarla ya que es una de las partes más indispensables a la hora de crear nuestra APIRest, palabras más, palabras menos; dicha anotación hace las veces de una llave que nos permite "conectar", en este caso, nuestro Repository con el servicio. En nuestro artículo (vídeo), se empleará todo el conjunto de métodos que parte de nuestro repositorio, y como de ahorrar código se trata, vamos a crear nuestro servicio por medio de las interfaces, no obstante, y partiendo de lo anterior, esta porción de código es por el cuál nos permite "inyectar" nuestro repositorio, al servicio:

@Autowired
UserRepository userRepository;

Todo archivo que esté asociado a un Servicio en SpringBoot, es indispensable el uso de la anotación @Service, para indicar que dicho elemento es un servicio como tal. Antes de proceder con la implementación del repositorio y del servicio en sí, para nuestra API Rest, se debe crear los siguientes paquetes, uno para el Repositorio y otro para el servicio:

Fig 1. - Procedimiento para agregar un paquete en Java (ampliar imágen - Parte 1)

Sólamente haciendo clic derecho del ratón en dónde está el paquete principal de nuestro proyecto, luego le damos en New ->Package, para luego desplegar un cuadro en dónde seleccionaremos Interface bajo los nombres de UserRepository y UserServiceInterface (este último nos ayuda cuándo vayamos a implementar los métodos de la interfaz UserServiceInterface, nos ayuda un montón a la hora de escribir código), Un submenú nos aparecerá después de haber realizado el procedimiento previo:

Fig 2. - Submenú para definir al usuario qué se va a crear

 La apariencia en la barra del explorador quedará así:

Fig 3. - Vista de la barra del explorador de IntelliJIDEA (Nótese que están las interfaces para el repositorio y el servicio)

Después de los pasos anteriormente descritos, vayamos al archivo UserRepository que está en el paquete del mismo nombre, y vamos a heredar todos los atributos de la clase JPARepository, además de implementar nuestras propias firmas (o clases en sí, porqué una interfaz es una plantilla para definir unas clases por el cuál el usuario debe definir que se va a hacer con ellas), antes de iniciar con la escritura o bien, la implementación en código, se debe colocar la anotación @Repository, encima de "public interface" para definir de que en sí, es un repositorio:

package com.toadsdewin.basicCrud.UserRepository;
import com.toadsdewin.basicCrud.UserModel.UserModel;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public interface UserRepository extends JpaRepository<UserModel,Long>
{
public List<UserModel> findByCountry(String country);
public List<UserModel> findByOccupation(String occupation);
public List<UserModel> findByProfession(String profession);
public List<UserModel> findByAge (Integer age);
}

Nuestro repositorio contiene todos los métodos heredados de la clase JPARepository, más otros tres que son definidos por nosotros como son:

  • findByCountry: lleva por parámetro un objeto de tipo String cuya palabra es country, nos indica el país por el que debemos buscar.
  • findByOccupation: el mismo significado que findByCountry, sólo que éste nos permite indexar la ocupación otorgada a la persona que se agregó en nuestra DB.
  • findByProfession: la misma función que findByCountry, sólo que ésta nos permite indexar la profesión de la persona que está en nuestra DB.
  • findByAge: lleva por parámetro un objeto de tipo Integer cuya palabra es age, nos indica que podemos buscar un listado de usuarios que tenga una determinada edad.
No obstante, nuestro repositorio llevan dos parámetros en un diamanta como se ve después de la palabra JPARepository, cada elemento pertenece a dos objetos, uno que es el nombre de la clase asociada al Modelo, y su segundo parámetro lleva consigo el tipo de dato u objeto al cuál está asociada nuestra llave primaria. Ahora bien, ¿Y cómo vamos a trasladar todos esos métodos a su respectivo servico?, no tienen que preocuparse, se los explicaré.

Vamos directamente a nuestro archivo UserServiceInterface, y escribiremos nuestro código tal como aparece a continuación:

package com.toadsdewin.basicCrud.UserService;
import com.toadsdewin.basicCrud.UserModel.UserModel;
import java.util.List;

public interface UserServiceInterface
{
public boolean deleteUser(Long id);
public List<UserModel> getUsers();
public List<UserModel> getByCountry(String country);
public List<UserModel> getByOccupation(String occupation);
public List<UserModel> getByProfession(String profession);
public List<UserModel> getByAge(Integer age);
public UserModel saveUser(UserModel user);
public UserModel upgradeUser(UserModel user,Long id);
public UserModel getById(Long id);
}

En esta interfaz de UserServiceInterface (valga la redundancia), tenemos nueve métodos compuestos de cuatro elementos de tipo List (de java.util.*), tres del tipo UserModel (viene del modelo), y un primitivo de tipo lógico o boolean. Al implementar nuestra interfaz, previa creación del código UserService y también de la implementación de nuestras anotaciones @Service y @Autowired, nos quedará de la siguiente forma, eso sí siguiendo los pasos dados a partir de la  Figura 1:

package com.toadsdewin.basicCrud.UserService;
import com.toadsdewin.basicCrud.UserModel.UserModel;
import com.toadsdewin.basicCrud.UserRepository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;

@Service
public class UserService implements UserServiceInterface
{
@Autowired
UserRepository userRepository;

@Override
public boolean deleteUser(Long id) {
try {
userRepository.deleteById(id);
return true;
}
catch (Exception error)
{
error.getMessage();
}
return false;
}
@Override
public List<UserModel> getUsers() {
return (List<UserModel>)userRepository.findAll();
}

@Override
public List<UserModel> getByCountry(String country) {
return userRepository.findByCountry(country);
}

@Override
public List<UserModel> getByOccupation(String occupation) {
return userRepository.findByOccupation(occupation);
}
@Override
public List<UserModel>getByProfession(String profession)
{
return userRepository.findByProfession(profession);
}

@Override
public List<UserModel> getByAge(Integer age) {
return userRepository.findByAge(age);
}

@Override
public UserModel saveUser(UserModel user) {
return userRepository.save(user);
}

@Override
public UserModel upgradeUser(UserModel user, Long id) {
try {
UserModel upgrade = userRepository.findById(id).get();

if (Objects.nonNull(user.getName()) && !"".equalsIgnoreCase(user.getName()))
{
upgrade.setName(user.getName());
}
if (Objects.nonNull(user.getSurname()) && !"".equalsIgnoreCase(user.getSurname()))
{
upgrade.setSurname(user.getSurname());
}
if (Objects.nonNull(user.getCountry()) && !"".equalsIgnoreCase(user.getCountry()))
{
upgrade.setCountry(user.getCountry());
}
if(Objects.nonNull(user.getOccupation()) && !"".equalsIgnoreCase(user.getOccupation()))
{
upgrade.setOccupation(user.getOccupation());
}
if(Objects.nonNull(user.getProfession())&& !"".equalsIgnoreCase(user.getProfession()))
{
upgrade.setProfession(user.getProfession());
}
if(Objects.nonNull((user.getAge()))&&! "".equals(user.getAge()))
{
upgrade.setAge(user.getAge());
}
return userRepository.save(upgrade);
}catch(Exception error)
{
error.getMessage();
}
return null;
}
@Override
public UserModel getById(Long id) {
return userRepository.findById(id).orElse(null);
}
}

Hasta el momento, esta es la parte de la implementación de nuestro repositorio y servicio, respectivamente; para que se vea realmente la ejecución de nuestros dos elementos, nos hace falta un elemento bien indispensable, se podría decir que es el santo grial del desarrollo de una API Rest con Spring Boot, y no es más que su @Controller, o controlador en sí, para esta última parte de nuestra implementación, les explicaré no solamente qué es y como funciona un controlador, sino que también voy a tocar el tema de los estados HTTP que aparecen en sus respectivas anotaciones aparte del @Controller. Eso sí, nos vemos en el siguiente post (vídeo).