Exposing existing API as a Web service - web-services

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?

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.

First of all, I would hesitate before exposing an existing API as a web service on a one-for-one basis. Was the existing API written to be accessed over a network? If not, then it was probably not designed with networking constraints in mind.
It may include method calls which will involve larger numbers of small operations - the kind that cost nothing when used within a single process. Over a network, each call has an associated latency that is much larger than the overhead of caling a method within the same process.
Instead, I would design a service to meet the functional requirements of the API. The service would likely be designed to have a smaller number of operations which perform more work per operation, thereby minimizing the overhead associated with network traffic. The service would likely be implemented by calling on the API (assuming it is written to handle multi-threaded environments like a service).
In terms of WSDL, the toolkit you are using may very well construct a WSDL for you. I know that WCF in .NET does that, and I have done the same using IBM Rational Web Developer, so I know that the Java world can do the same.
Otherwise, it's not actually that hard to hand-write a WSDL and corresponding schema. In either case, they do need to be provided so that your clients can consume the service.
There's nothing wrong with using REST for this if your API can be cleanly expressed as a set of operations on resources. In this case, yes, provide the schema to make it easier for your clients to process the XML. I would beware of forcing your API to fit the REST model if it is not cleanly expressible as operations on resources.

Related

CDI Inject in Stateless Session Beans requests

Currently we have an elaborate POJO object structure for handling a webservice request, called a 'processor'.
Remote and Local EJB's and PersistenceContext called during serving this request are initialized in the statless bean and handed to this 'processors' constructor which is re-created during each webservice request.
If I do not want to revert to JNDI lookups deep down in my 'processor' I keep on dragging around all these EJB's through my code.
Enter CDI. I would like to be able to inject these EJB's whenever I need them in this 'processor'.
However, I also noticed this means that the current 'processor' has to become a CDI bean itselve: so, using the #Inject in the Stateless Session Bean that implements the webservice.
When I do this the entiry lifecycle of the processor becomes bound to the bean and not to the request its serving.
Suddenly I have to take into consideration that I should not retain state (other than the injected objects) in the processor, since this state will be shared between multiple webservice invocations. As a programmer, this is not making my life more easy.
So: how should I go about doing this? I've read about the scoping but I'm not sure how / if this would be helping me.
Example, stateless bean:
#Stateless
#WebService
public class ExampleBean {
#Inject
Processor requestScopedInstance;
int beanDependentScopeCounter;
public String sayHello() {
System.out.println( "bean object id: " + this.toString() );
return requestScopedInstance.sayHello(beanDependentScopeCounter++);
}
}
interface:
public interface Processor {
String sayHello(int beanScopedCounter);
}
Implementation:
public class ProcessorImpl implements Processor {
private int requestScopedCounter = 0;
#Override
public String sayHello(int beanScopedCounter) {
return "test, requestScoped: " + requestScopedCounter++ + ", beansScoped: " + beanScopedCounter;
}
}
When I do this the entiry lifecycle of the processor becomes bound to the bean and not to the request its serving that is not correct. That is only the case if you don't use #ApplicationScoped, #SessionScoped, #RequestScoped.
So:
Annotate your processor with #RequestScoped.
You don't need to hand over the EJBs, you can just inject them, where needed.
Use #PostConstruct annotated methods for constructor-code which uses injected objects.
stateless POJOs can be annotated #ApplicationScoped, not stateless POJOs can stay dependent-scoped which is default.
That is made possible because proxies are injected, not actual beans. Using these proxies CDI makes sure that the correct scope is used for your particular calls.

Http Post with WebAPI Causing "The HttpOperationHandlerFactory is unable to determine the input parameter..."

I have a method that is receiving more than one parameter. The method signature with attributes look like the following:
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
public int AddUser(string firstName, string lastName, string emailaddress) { // actions here }
However, when I use this method, I get the following exception:
The HttpOperationHandlerFactory is unable to determine the input
parameter that should be associated with the request message content
for service operation 'Initiate'. If the operation does not expect
content in the request message use the HTTP GET method with the
operation. Otherwise, ensure that one input parameter either has it's
IsContentParameter property set to 'True' or is a type that is
assignable to one of the following: HttpContent, ObjectContent`1,
So, I've created a custom object (such as below) to be passed in.
[DataContract]
public class UserToAdd {
[DataMember] public string firstName { get; set; }
[DataMember] public string lastName { get; set; }
[DataMember] public string emailAddress { get; set; }
}
Using this new signature:
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
public int AddUser(UserToAdd user) { // actions here }
When I do that, I get a 404. It seems I can't win. Any suggestions?
If you want to create routes declaratively you can. I had to do this as I had inherited a bunch of non-restful URIs that had to be supported for backwards compatibility reasons. I created my own attribute to describe URIs, constraints and HTTP methods. This is effectively a replacement for WebInvoke/WebGet. I reflect over my service methods on start-up to discover routes and call MapHttpRoute() as appropriate. Each of my routes specifies the controller and action explicitly. This approach is good for RPC style APIs, but it required quite a lot of heavy lifting. The nice part is that it keeps the definition of routes with the methods - this is not something web api gives you explicitly.
So whilst RPC style is possible, it's not idiomatic. Web API is strongly biased out of the box towards RESTful APIs with convention driven mapping of routes to services and methods - in this way very generic routes are registered and conventions do the rest. That largely avoids the issues of defining routes away from their corresponding actions. If you can I would convert to the RESTful/convention approach of Web API, as you are otherwise fighting the framework a little.

Passing Objects to a Web Service's method

I have recently started working on (Java)Web Services.
I have certain web methods that accept different arguments - primitives,Maps,HttpServletRequest,FlowJob(Spring) etc.
I got numerous issues while attempting this - from a failed web service deployment saying 'interfaces not supported by JAX-WS' to runtime exceptions 'java.lang.Object cannot be cast to org.w3c.dom.Element' !
I have not put the steps deliberately;all I need to know is that is it possible to pass the above arguments to a Java Web Service method? In short,is something like this possible :
#WebService(serviceName = "WS")
public class WS {
#WebMethod
public Object processJob(MapargsMap){
}
#WebMethod
public String processJob(SomeCustomObject object){
}
}
}
Are there any work-arounds to make JAXB marshal and unmarshal custom objects,Maps etc.?If yes,what are they?
Thanks & regards !

What Java library that would auto-generate all the boiler-plate code for calling Web Service?

There is wsimport command that generates all the types referenced in WSDL. But this does not do anything with all the remaining boilerplate of calling a web service method, parsing XML into Java objects etc.
Suppose a web service as defined by the service provider WSDL called CustomerService provides an operation getCustomerAddress(String CustomerID) and returns object of type CustomerAddress.
wsimport only generates types such as CustomerAddress. What I am looking for is auto-generated code like:
String AppID = "" ; // autogenerated (if there was such parameter specified in WSDL)
String endpointA = "some end point";
CustomerAddress getCustomerAddress(String customerID) {
// all the bolierplate of actaully calling the webservice, unmarshalling the XML response
// including error/exception handling etc.
return result;
}
I like Spring web services, especially if you're already using Spring.

Generating stub classes for 3rd party WS

I need to incorporate a pretty complex 3rd party web service into my Grails app. My plan was to use WSDL2Java to generate the stub classes from the wsdl, and this was the method recommended in the 3rd party's documentation (complete with examples). First i tried to use the Axis2 codegen plugin for Eclipse but eventually came up against an InvocationTargetexception. I debugged the plugin and found it was because the wsdl is defined with RPC encoding.
Some people have recommended using Axis 1.4 instead, so I've now installed that too but have come up against an IO Exception - Type {http://xml.apache.org/xml-soap}DataHandler is referenced but not defined.
Can anyone suggest a method for creating the java classes from this wsdl without having to hack the wsdl apart?
I ended up using the Axis2 wdsl2java and copying the required annotated code into the service and used the CXF plugin. I also put in my service the following code
static expose=['cxfjax']
The reason why I had to do this was because there was a "complicated" (for grails) structure my methods look like
#WebMethod(operationName = "authenticate", action = "http://betterhidethis/authenticate")
#WebResult(name = "authenticateResult", targetNamespace = "http:/betterhidethis/")
public ArrayOfString authenticate(
#WebParam(name = "strUserName", targetNamespace = "http://betterhidethis/")
String strUserName,
#WebParam(name = "strPassword", targetNamespace = "http://betterhidethis/")
String strPassword) {
Of cause the Geneerator also created the ArrayOfString class which I use later.
Hope this helps.