API REST 4. Calidad al implementar aplicacion Web

Introducción

Existen 3 niveles para aplicar API REST en el desarrollo de una Aplicación Web.
Cumplir con estás nos garantiza las mejores practicas para su implementación, integración, estabilidad y escabilidad.
Para detalles se puede consultar  http://asiermarques.com/2013/conceptos-sobre-apis-rest/

Nivel 1. Uso correcto de URIs

  1. Identificar de forma única el recurso
  2. Las URI no deben contener acciones
  3. Independientes del formato
  4. Jerarquía lógica
  5. Los filtrados no se deben hacer en la URI

Nivel 2. HTTP

  1. Usar métodos HTTP; GET, POST, PUT, DELETE y PATCH
  2. Código de estado
  3. Aceptación de tipos de contenido

Nivel 3. Hypermedia

Se vera mas a detalle posteriormente.

Con lo que llevamos hasta este momento, podemos generar un proyecto de API REST en Web con las mejores practicas.
Vamos a retomar la tabla Persona y crear un Sistema Web con API REST para administrar personas; crear, leer, actualizar y eliminar.

Construir aplicación

Crear proyecto

Ir a

File -> New -> Other… -> Spring Boot -> Spring Starter Project

Seleccionamos nombre del proyecto, tipo, versión de java, paquete, entre otras opciones. Clic en Next>. Seleccionamos la versión de Spring Boot y las dependencias:

  1. JPA
  2. H2
  3. MySQL
  4. Web

Clic en Next> y posteriormente clic en Finish.

Crear paquetes

Creamos los paquetes

  • com.mio.administrar.controller
  • com.mio.administrar.repository
  • com.mio.administrar.entity

Copiar clases e interfaces

Tomando las clases e interfaces del proyecto anterior https://github.com/arielolivagh/gs-rest-service-complete/tree/v2.0  copiamos:

  • La clase PersonaController al paquete com.mio.administrar.controller
  • La interface PersonaRepository al paquete com.mio.administrar.repository
  • La clase Persona al paquete com.mio.administrar.entity

Conexión a la Base de Datos

Escribimos los parámetros de conexión a la Base de Datos en el archivo application.properties.

spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/Pruebas
spring.datasource.username=root
spring.datasource.password=root

Crear consulta para búsqueda de personas por id

En la clase repository vamos a crear un nuevo query para obtener una persona por su id.

@Query("select p from Persona p where p.idPersona = ?1")
Persona findPersona(int id);

Crear controller de calidad

Crear personas

  • Método POST
  • La respuesta es Json
  • Documentación JavaDoc
    /**
     * Crea una persona: POST http://{servidor}:{puerto}/persona
     * @param nombre Nombre de la persona
     * @param edad Edad de la persona
     * @param sexo Sexo de la persona
     * @return mensaje de 'Agregado correctamente'
     */
    @RequestMapping(method=RequestMethod.POST,produces={"application/json"})
    public String createPersona(@RequestParam String nombre,@RequestParam int edad,@RequestParam String sexo) {
            Persona p = new Persona();
    	p.setNombre(nombre);
    	p.setEdad(edad);
    	p.setSexo(sexo);
    	personaRepository.save(p);
    		
            return "Agregado correctamente";
    }

    Consumir:

    curl -i -X POST -d "nombre=Mariel&edad=51&sexo=F" http://localhost:8080/persona

Leer todas las personas

  • Método GET
  • La respuesta es Json
  • ocumentación JavaDoc
    /**
     * Obtiene todas las personas: GET http://{servidor}:{puerto}/persona
     * @return Lista de personas
     */
     @RequestMapping(method=RequestMethod.GET,produces={"application/json"})
        public Iterable<Persona> readPersonas() {
        return personaRepository.findAll();
     }

    Consumir:

    curl -i -X GET http://localhost:8080/persona

Leer una persona

  • Método GET
  • La respuesta es Json
  • Documentación JavaDoc
    /**
     * Obtiene una person por id: GET http://{servidor}:{puerto}/persona/{id}
     * @param id Id de la persona. En la Url
     * @return Una personas
     */
     @RequestMapping(value="/{id}",method=RequestMethod.GET,produces={"application/json"})
        public Persona readPersonaById(@PathVariable("id") int id) {
        return personaRepository.findPersona(id);
     }

    Consumir:

    curl -i -X GET http://localhost:8080/persona/7

Actualiza una persona

  • Método PUT
  • La respuesta es Json
  • Documentación JavaDoc
    /**
     * Actualiza una persona por Id: PUT http://{servidor}:{puerto}/persona/{id}
     * @param id Id de la persona. En la Url
     * @param nombre Nombre de la persona
     * @param edad Edad de la persona
     * @param sexo Sexo de la person
     * @return mensaje de 'Actualizado correctamente'
     */
     @RequestMapping(value="/{id}",method=RequestMethod.PUT,produces={"application/json"})
     public String updatePersona(@RequestParam String nombre,@RequestParam int edad,@RequestParam String sexo,@PathVariable("id") int id) {
        Persona p = new Persona();
        p.setIdPersona(id);
        p.setNombre(nombre);
        p.setEdad(edad);
        p.setSexo(sexo);
        personaRepository.save(p);
        return "Actualizado correctamente";
     }

    Consumir:

    curl -i -X PUT -d "nombre=Ariel&edad=100&sexo=M" http://localhost:8080/persona/7

Actualiza edad de una persona

  • Método PATCH
  • La respuesta es Json
  • Documentación JavaDoc
    /**
     * Actualiza la edad de una persona por Id: PATCH http://{servidor}:{puerto}/persona/{id}
     * @param id Id de la persona. En la Url
     * @param edad Edad de la persona
     * @return mensaje de 'Actualizando la edad correctamente'
     */
     @RequestMapping(value="/{id}",method=RequestMethod.PATCH,produces={"application/json"})
     public String updateParcialPersona(@PathVariable("id") int id,@RequestParam int edad) {
        Persona p = personaRepository.findPersona(id);
        p.setEdad(edad);
        personaRepository.save(p);
        return "Actualizando la edad correctamente";
     }

    Consumir:

    curl -i -X PATCH -d "edad=10" http://localhost:8080/persona/7

Elimina todas las personas

  • Método DELETE
  • La respuesta es Json
  • Documentación JavaDoc
    /**
     * Elimina todas las personas: DELETE http://{servidor}:{puerto}/persona
     * @return mensaje de 'Todo eliminado correctamente'
     */
     @RequestMapping(method=RequestMethod.DELETE,produces={"application/json"})
        public String deleteAllPersona() {
        personaRepository.deleteAll();
        return "Todo eliminado correctamente";
     }

    Consumir:

    curl -i -X DELETE http://localhost:8080/persona

Elimina una persona

  • Método DELETE
  • La respuesta es Json
  • Documentación JavaDoc
    /**
     * Elimina una persona por id: DELETE http://{servidor}:{puerto}/persona/{id}
     * @param id Id de la persona. En la Url
     * @return mensaje de 'Eliminado correctamente'
     */
     @RequestMapping(value="/{id}", method=RequestMethod.DELETE,produces={"application/json"})
     public String deletePersona(@PathVariable("id") int id) {
        Persona p = new Persona();
        p.setIdPersona(id);
        personaRepository.delete(p);
        return "Eliminado correctamente";
     }

    Consumir:

    curl -i -X DELETE http://localhost:8080/persona/7

Otras

Descargar proyecto

Se puede descargar el proyecto completo de https://github.com/arielolivagh/administrarPersona/tree/v1.0

API REST 3. Publicar y consumir

Descripción

Publicar y consumir algunos métodos creados del API REST.

Publicar y Consumir

Usando CRUD

Simplemente usando los métodos que ya nos proporciona el CRUD

Crear Persona

Insertamos un nuevo registro a la tabla Persona.

  1. En la clase PersonaController
  2. Se mapea con /add
  3. Recibe los parámetros nombre, edad y sexo
  4. Se carga el Objeto Persona y se ejecuta la función save().
  5. Retorna el mensaje Agregado correctamente.
    @RequestMapping("/add")
    public String addPersona(@RequestParam  String nombre,@RequestParam  int edad,@RequestParam  String sexo) {
       Persona p = new Persona();
       p.setNombre(nombre);
       p.setEdad(edad);
       p.setSexo(sexo);
       personaRepository.save(p);
    		
       return "Agregado correctamente";
    }

     

Resultado

Consultar todas las Personas

Consultamos todos los registros de la tabla Persona.

  1. En la clase PersonaController
  2. Se mapea con /all
  3. No recibe parámetros
  4. Retorna el resultado de la función findAll().
    @RequestMapping("/all")
       public Iterable<Persona> getPersona() {
       return personaRepository.findAll();
    }

Resultado

Borra una Persona

Borramos un registro de la tabla Persona.

  1. En la clase PersonaController
  2. Se mapea con /delete
  3. Recibe el parámetro id
  4. Se carga el Objeto Persona y se ejecuta la función delete().
  5. Retorna el mensaje Borrado correctamente.
    @RequestMapping("/delete")
     public String deletePersona(@RequestParam int id) {
     Persona p = new Persona();
     p.setIdPersona(id);
     personaRepository.delete(p);
     return "Borrado correctamente";
     }
    

Resultado

Total de Personas

Total de registros de la tabla Persona.

  1. En la clase PersonaController
  2. Se mapea con /total
  3. No recibe parámetros
  4. Retorna el resultado de la función count().
    @RequestMapping("/total")
       public long totalPersona() { 
       return personaRepository.count();
    }

Resultado

Creamos consultas propias

Podemos crear otras consultas de acuerdo a nuestras necesidades

Persona por tipo de sexo

Obtenemos las Personas por su tipo de sexo

  1. En la interface PersonaRepository agregamos la consulta que filtra por tipo de sexo
    @Query("select p from Persona p where p.sexo = ?1")
    Iterable<Persona> findBySexo(String sexo);
  2. En la clase PersonaController
  3. Se mapea con /allBySexo
  4. Recibe el parámetro sexo
  5. Retorna el resultado de la función findBySexo().
    @RequestMapping("/allBySexo")
    public Iterable<Persona> getPersonaBySexo(@RequestParam String sexo) {
       return personaRepository.findBySexo(sexo);
    }

Resultado

Persona por tipo de sexo con paginado

Obtenemos las Personas por su tipo de sexo. Los resultados se muestran paginados.

  1. En la interface PersonaRepository agregamos la consulta que filtra por tipo de sexo y agrega paginado.
    @Query("select p from Persona p where p.sexo = ?1")
    Page<Iterable<Persona>> findBySexoPag(@Param("sexo") String sexo,Pageable pageable);
  2. En la clase PersonaController
  3. Se mapea con /sexoPag
  4. Recibe los parámetros sexo, inicio y bloque. Estos 2 últimos parámetros para el paginado.
  5. Se pasa los parámetros de paginado a la función findBySexoPag()
  6. Retorna el resultado de la función findBySexoPag().
    @RequestMapping(value="/sexoPag")
       public Page<Iterable<Persona>> personaPag(@RequestParam String sexo,@RequestParam int inicio,@RequestParam int bloque) {
       return personaRepository.findBySexoPag(sexo, new PageRequest(inicio, bloque));
    }

Resultado

Persona por tipo de sexo con paginado y ordenado por un campo

Obtenemos las Personas por su tipo de sexo. Los resultados se muestran paginados y ordenados por un campo.

  1. En la clase PersonaController
  2. Se mapea con /sexoOrder
  3. Recibe los parámetros sexo, inicio, bloque y orden.
  4. Se pasa los parámetros de paginado y orden a la función findBySexoPag()
  5. Retorna el resultado de la función findBySexoPag().
    @RequestMapping(value="/sexoOrder")
       public Page<Iterable<Persona>> personaOrder(@RequestParam String sexo,@RequestParam int inicio,@RequestParam int bloque,@RequestParam String orden) {
       return personaRepository.findBySexoPag(sexo, new PageRequest(inicio, bloque,Sort.Direction.ASC, orden));
    }

Resultado

Otras opciones

Podemos crear otras consultas con otros métodos HTTP; POST, PUT, DELETE  o PATCH. También enviando HEAD en la petición.

Agregar Persona con el método POST

@RequestMapping(value="/add",method=RequestMethod.POST)
   public String addPersonaPost(@RequestParam  String nombre,@RequestParam  int edad,@RequestParam  String sexo) {
   Persona p = new Persona();
   p.setNombre(nombre);
   p.setEdad(edad);
   p.setSexo(sexo);
   personaRepository.save(p);
   return "Agregado correctamente";
}

Resultado. Utilizando curl:

Obtener Personas del sexo=M mediante HEAD

@RequestMapping(value="/sexo",headers={"sexo=M"})
   public Iterable<Persona> personaM() {
   return personaRepository.findBySexo("M");
}

Resultado. Utilizando curl:

Otros

Descargar Proyecto

Se puede descargar el proyecto completo de https://github.com/arielolivagh/gs-rest-service-complete/tree/v2.0