openxava / documentación / Lección 22: Llamada REST desde una validación

Curso: 1. Primeros pasos | 2. Modelo básico del dominio (1) | 3. Modelo básico del dominio (2) | 4. Refinar la interfaz de usuario | 5. Desarrollo ágil | 6. Herencia de superclases mapedas | 7. Herencia de entidades | 8. Herencia de vistas | 9. Propiedades Java | 10. Propiedades calculadas | 11. @DefaultValueCalculator en colecciones | 12. @Calculation y totales de colección | 13. @DefaultValueCalculator desde archivo | 14. Evolución del esquema manual | 15. Cálculo de valor por defecto multiusuario | 16. Sincronizar propiedades persistentes y calculadas | 17. Lógica desde la base de datos | 18. Validando con @EntityValidator | 19. Alternativas de validación  | 20. Validación al borrar  21. Anotación Bean Validation propia | 22: Llamada REST desde una validación | 23. Atributos en anotaciones  | 24. Refinar el comportamiento predefinido | 25. Comportamiento y lógica de negocio | 26. Referencias y colecciones | A. Arquitectura y filosofía | B. Java Persistence API | C. Anotaciones | D. Pruebas automáticas

Tabla de contenidos

Lección 22: Llamada REST desde una validación
Llamar a un servicio web REST para validar el ISBN
Resumen
En la lección anterior vistes como crear una anotación Bean Validation propia. En esta leccion verás como se llama a un servicio web REST para validar el ISBN.

Si no te gustan los videos sigue las instrucciones a continuación.

Llamar a un servicio web REST para validar el ISBN

Aunque la mayoría de los validadores tienen una lógica simple, puedes crear validadores con una lógica compleja si lo necesitas. Por ejemplo, en el caso de nuestro ISBN, queremos, no sólo verificar el formato correcto, sino también comprobar que existe de verdad un libro con ese ISBN. Una forma de hacer esto es usando servicios web.
Como seguramente ya sepas, un servicio web es una funcionalidad que reside en un servidor web y que tú puedes llamar desde tu programa. La forma tradicional de desarrollar servicios web es mediante los estándares WS-*, como SOAP, UDDI, etc. Aunque, hoy en día, la forma más simple de desarrollar servicios es REST. REST consiste básicamente en usar la ya existente “forma de trabajar” de internet para comunicación entre programas. Llamar a un servicio REST consiste en usar una URL web convencional para obtener un recurso de un servidor web. Este recurso usualmente contiene datos en formato XML, HTML, JSON, etc. En otras palabras, los programas usan internet de la misma manera que lo hacen los usuarios con sus navegadores.
Hay bastantes sitio con servicios web SOAP y REST para consultar el ISBN de un libro, vamos a usar openlibrary.org que proporciona una API REST gratuita para consultar su catálogo de libros. Para probar la API de Open Library abre un navegador y ve a la siguiente URL:
https://openlibrary.org/api/books?jscmd=data&format=json&bibkeys=ISBN:9780932633439
Donde el último parámetro es el ISBN del libro, a partir del cual obtenemos un JSON con los datos del libro, algo como esto:
validation040.png
Un JSON es simplemente data con clave/valor que usa {} y [] para anidar y repetir. Si intentas obtener los datos de un libro inexistente, como en esta URL:
https://openlibrary.org/api/books?jscmd=data&format=json&bibkeys=ISBN:9791034369997
Obtienes un JSON vacío, como este:
validation050.png
Es decir, un JSON vacío, simplemente unas llaves vacías, así: {}.
Para llamar a este servicio web usaremos JAX-RS. JAX-RS es el estándar Java para llamar a servicios web REST. OpenXava incluye soporte para llamar a servicios web usando JAX-RS, por lo que no necesitas añadir ninguna librería adicional.
Modifiquemos ValidadorISBN para usar este servicio REST. Veamos el resultado:
package com.tuempresa.facturacion.validadores; 

import javax.validation.*;
import javax.ws.rs.client.*; // Para usar JAX-RS
import com.tuempresa.facturacion.anotaciones.*;
import org.apache.commons.logging.*; // Para usar Log
import org.openxava.util.*;
 
public class ValidadorISBN
    implements ConstraintValidator<ISBN, Object> {
	
    private static Log log = LogFactory.getLog(ValidadorISBN.class); // Instancia 'log'
 
    private static org.apache.commons.validator.routines.ISBNValidator
        validador = 
            new org.apache.commons.validator.routines.ISBNValidator();
 
    public void initialize(ISBN isbn) {
 
    }
 
    public boolean isValid(Object valor, ConstraintValidatorContext contexto) {
        if (Is.empty(valor)) return true;
        if (!validador.isValid(valor.toString())) return false;
        return existeISBN(valor); // Aquí hacemos la llamada REST
    }
    
    private boolean existeISBN(Object isbn) {
        try {
            // Aquí usamos JAX-RS para llamar al servicio REST
            String respuesta = ClientBuilder.newClient()
                .target("http://openlibrary.org/") // El sitio
                .path("/api/books") // La ruta del servicio
                .queryParam("jscmd", "data") // Los parámetros
                .queryParam("format", "json")
                .queryParam("bibkeys", "ISBN:" + isbn) // El ISBN es un parámetro
                .request()
                .get(String.class); // Una cadena con el JSON
            return !respuesta.equals("{}"); // ¿Está el JSON vacío? Suficiente para nuestro caso
        }
        catch (Exception ex) {
            log.warn("Imposible conectar a openlibrary.org " +
                "para validar el ISBN. Validación fallida", ex);
            return false; // Si hay errores asumimos que la validación falla
        }
    }
    
}
Simplemente abrimos la URL con el ISBN como parámetro de la petición. Si el JSON resultante es un JSON vacío, es decir {}, la búsqueda ha fallado, en caso contrario hemos encontrado el libro. Para nuestro caso, obtener el JSON como una cadena para poder hacer una comparación simple es el camino más corto, sin embargo JAX-RS permite convertir el JSON en un objeto Java de tu propia clase (Libro por ejemplo) rellenando las propiedades correspondientes, sólo has de usar .get(Libro.class) en lugar de .get(String.class) como última línea de la llamada.
Prueba ahora tu aplicación y verás como si introduces un ISBN no existente la validación falla.

Resumen

¡Enhorabuena! Has aprendido como llamar a un servicio web REST para validar el ISBN. En la siguiente lección vas a aprender a como añadir atributos a tu anotación.

Descargar código fuente de esta lección

¿Problemas con la lección? Pregunta en el foro ¿Ha ido bien? Ve a la leccion 23