Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exposing existing API as a Web service

I am currently working on a task to expose an API as a Web service. The idea here is to package the existing business logic in JAR files into a WAR file and expose the WAR file as a Web service that would return a free-form XML string. When we expose an existing API as a Web service, is it sufficient that we make available an XSD & WSDL file of the returned XML string data? Is that the convention or the standard practice?

like image 924
Subramanian Avatar asked Dec 06 '22 23:12

Subramanian


1 Answers

It depends on whether or not you are using SOAP or REST. SOAP is more restrictive; as a result, it's more expected that you'll have a WSDL file to generate the classes that interface with the API.

On the other hand, if you are using REST, just exposing a RESTful URI would be considered enough to meet the constraint of a RESTful web service having a uniform interface.

REST tends to be gaining more ground over SOAP since it is a permissive architectural style. I would prefer this method, and I would recommend this method if you're new to developing web services.

Depending on what language you are using, I'm assuming Java, you can use Restlets or Spring 3.0's REST framework to help you build a RESTful web service. These tools really make that job a lot easier and help you conform to the 6 Constraints of a RESTful Web Service and meet the 4 Key Goals.

UPDATE:

Assuming you already have existing, object-oriented code, and assuming you want to expose that code as a REST API, using Spring 3.0 MVC, create a Controller subclass that will wrap around your existing package:

Example GET:

Resource: Javadocs for Jackson's ObjectMapper POJO/JSON Marshaller

 // this is the wrapper around your existing Java packages.  
 @Controller
 public class UserController {

     protected static final DATA_TYPE = "json";

     // In REST, GET method is used to retrieve data with no side effects, 
         // meaning that no changes are made to the data on the server.
     @RequestMapping(value="/users/{username}", method=RequestMethod.GET)
     public void getUserData(@PathVariable("username") String userName, Model model) {

         // this is your existing class
         UserDataService userDataService = new UserDataService();

         // assume you have a class User, and getUserDetails gives you that POJO object.
         User user = userDataService.getUserDetails(username);


         // marshal the User object to JSON, using Jackson, and write as output in response
         ObjectMapper mapper = new ObjectMapper();
         mapper.writeValue(response.getWriter(), user);

     }
 }

 // assume you have an existing POJO class called User
 class User implements Serializable {

     String username;
     String age;
     String birthday;
     String mood;

     String getMood() { return this.mood; }
     String getBirthday() { return this.birthday; }
     String getAge() { return this.age; }
     String getUsername() { return this.username; }

     String setMood(String mood) { this.mood = mood; }
     String setBirthday(String birthday) { this.birthday = birthday; }
     String setAge(String age) { this.age = age; }
     String setUsername(String username) { this.username = username; }
}

Request:

http://api.example.com:8080/users/jmort253/

Response:

{ 
    "username":"jmort253",
    "mood":"good",
    "age":"not too old and not too young",
    "birthday","Jan 1, 1900"
}

XML instead of JSON:

The main difference between returning XML and returning JSON is in the marshaller used. Using javax.xml.bind.annotations, you can place annotations on the POJO class so the marshaller can convert it to XML, freeing you up from the details of having to manually code XML by hand:

Using javax.xml.bind.annotations to convert Java Objects to XML and XSD. This resource also explains how to generate the XML Schema, if you deem that as a requirement to your REST Web service.

 @XmlRootElement
 class User implements Serializable {

     String username;
     String age;
     String birthday;
     String mood;

     String getMood() { return this.mood; }
     String getBirthday() { return this.birthday; }
     String getAge() { return this.age; }
     String getUsername() { return this.username; }

     String setMood(String mood) { this.mood = mood; }
     String setBirthday(String birthday) { this.birthday = birthday; }
     String setAge(String age) { this.age = age; }
     String setUsername(String username) { this.username = username; }
}

Instead of using the Jackson API's ObjectMapper class to marshal the POJO class to JSON, use the javax.xml.bind.annotations package in place of ObjectMapper:

JAXBContext context = JAXBContext.newInstance(User.class);
Marshaller marshaller = context.createMarshaller();

// pretty print XML
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
marshaller.marshal(user, System.out);

Aside from the other resources, this article has a few examples that use JAXB to deserialize an ArrayList of POJO objects to XML.

My final suggestion when working on the REST Web service wrappers is to set your logging levels to "ALL" or "DEBUG". I find that this helps me more easily determine the root cause of any problems I face when setting up a Web service. The libraries themselves will output helpful debug messages to help you resolve configuration issues, such as missing dependencies, missing annotations, and other issues that you'll likely encounter when dealing with the conversion to XML/JSON process or in setting up Spring 3.0.

Once you're uniform interfaces are setup and you can make GET requests and receive responses, you can then set the logging levels back to the previous INFO or WARN levels.

like image 96
jmort253 Avatar answered Mar 21 '23 00:03

jmort253