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:
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:
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:
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.