openxava / documentation / Lesson 22: REST service call from validation

Course: 1. Getting started | 2. Basic domain model (1) | 3. Basic domain model (2) | 4. Refining the user interface | 5. Agile development6. Mapped superclass inheritance | 7. Entity inheritance | 8. View inheritance | 9. Java properties | 10. Calculated properties | 11. @DefaultValueCalculator in collections | 12. @Calculation and collections totals | 13. @DefaultValueCalculator from file | 14. Manual schema evolution | 15. Multi user default value calculation | 16. Synchronize persistent and computed propierties | 17. Logic from database  | 18. Validating with @EntityValidator 19. Validation alternatives  | 20. Validation on remove  21. Custom Bean Validation annotation  | 22. REST service call from validation | 23. Attributes in annotations  | 24. Refining the standard behavior | 25. Behavior & business logic | 26. References & collections | A. Architecture & philosophy | B. Java Persistence API | C. Annotations | D. Automated testing

Table of contents

Lesson 22: REST service call from validation
Call to a REST web service to validate the ISBN
Summary
In the last lesson you saw how to create your custom Bean Validation annotation. In this lesson you will see how to call a REST web service to validate the ISBN.

If you don't like videos follow the instructions below.

Call to a REST web service to validate the ISBN

Though most validators have simple logic, you can create validator with complex logic if necessary. For example, in the case of our ISBN, we want, not only to verify the correct format, but also to check that a book with that ISBN actually exists. A way to do this is by using web services.
As you already know, a web service is a functionality hosted in web servers and can be called by a program. The traditional way to develop and use web services is by means of WS-* standards, like SOAP, UDDI, etc., although, the simplest way to develop services today is REST. The basic idea of REST is to use the already existing “way to work” of the internet for inter-program communication. Calling a REST service consists of using a regular web URL to get a resource from a web server; this resource is usually data in XML, HTML, JSON or any other format. In other words, the programs use the internet just as regular users with their browsers.
There are a lot of sites with SOAP and REST web services that enable us to consult a book ISBN, we're going to use openlibrary.org that provides a free REST API to consult its book catalog. To try the Open Library API open a browser and go to the next URL:
https://openlibrary.org/api/books?jscmd=data&format=json&bibkeys=ISBN:9780932633439
Where the last parameter is the ISBN of the book, from it you will get a JSON with the data of the book, something like this:
validation040.png
A JSON is just data with key/value using {} and [] for nesting and repeating. If you try to get the data of a non-existen book, like in this URL:
https://openlibrary.org/api/books?jscmd=data&format=json&bibkeys=ISBN:9791034369997
You'll get an empty JSON, like this:
validation050.png
That is, an empty JSON, just {}.
To call this web service we'll use JAX-RS. JAX-RS is the Java standard to call REST web services. OpenXava includes support to call web services using JAX-RS, so you don't need to add any additional library.
Let's modify ISBNValidator to use this REST service. See the result:
package com.yourcompany.invoicing.validators; 

import javax.validation.*;
import javax.ws.rs.client.*; // To use JAX-RS
import com.yourcompany.invoicing.annotations.*;
import org.apache.commons.logging.*; // To use Log
import org.openxava.util.*;
 
public class ISBNValidator
    implements ConstraintValidator<ISBN, Object> {
	
    private static Log log = LogFactory.getLog(ISBNValidator.class); // Instantiate 'log'
 
    private static org.apache.commons.validator.routines.ISBNValidator
        validator = 
            new org.apache.commons.validator.routines.ISBNValidator();
 
    public void initialize(ISBN isbn) {
 
    }
 
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if (Is.empty(value)) return true;
        if (!validator.isValid(value.toString())) return false;
        return isbnExists(value); // Here we do the REST call
    }
    
    private boolean isbnExists(Object isbn) {
        try {
            // Here we use JAX-RS to call a REST service
            String response = ClientBuilder.newClient()
                .target("http://openlibrary.org/") // The site
                .path("/api/books") // The path of the service
                .queryParam("jscmd", "data") // Parameters
                .queryParam("format", "json")
                .queryParam("bibkeys", "ISBN:" + isbn) // The ISBN is a parameter
                .request()
                .get(String.class); // A String with the JSON
            return !response.equals("{}"); // Is the JSON empty? Enough for our case.
        }
        catch (Exception ex) {
            log.warn("Impossible to connect to openlibrary.org " +
                "to validate the ISBN. Validation fails", ex);
            return false; // If there are errors we assume that validation fails
        }
    }
    
}
We simply open the URL with the ISBN as the request parameter. If the resulting JSON is an empty JSON, that is {}, the search has failed, otherwise we have found the book. For this case, getting the JSON as a String to do a simple comparison is the simplest approach, however JAX-RS could parse the JSON as a Java object of your own class (Book for example) filling the corresponding properties, just use .get(Book.class) instead of .get(String.class) as last line of the call.
Try out your application now and you'll see that the validation will fail if you enter a non-existent ISBN.

Summary

Congratulations! You have learned how to call a REST web service to validate the ISBN. In the next lesson you are going to learn how to add attributes in annotations. 

Download source code of this lesson

Any problem with this lesson? Ask in the forum Everything fine? Go to lesson 23