Web Services Interview Questions and Answers - RESTful Web Service Overview
Q. Why would you use a RESTful Web service?
A. RESTful Web service is easy, straightforward, supports multiple data formats like XML, JSON, etc and easily testable. For example,
It can be tested by
1. Directly invoking the service from the browser by typing a URL if the RESTFul service supports GET request with query parameters. For example,
http://localhost:8080/executionservices/execution/1.0/order/create?accountId=123&qty=25
2. You could use a Firefox plugin like "poster" to post an XML request to your service.
3. You could write a Web Service client to consume the Web service from a test class or a separate application client. You could use libraries like HttpClient, CXF Client, URLConnection, etc to connect to the RESTful service.
Q. What are the various implementations of JAX-RS available to choose from in Java?
A. When you're developing with REST in Java, you have a lot of options to choose from in terms of the frameworks. There's Jersey, the reference implementation from Oracle, then you have RestEasy, the JBoss choice, and there is CXF, the Apache choice.
Q. How would you go about implemnting the RESTful Web service using the framework of your choice?
A. Let's look at CXF as it is easy to configure. The steps involved include
- Bringing in the relevant framework jar files for Spring and CXF. For example, via Maven using a pom.xml file.
- If the request and responses are XML based POST, then define an XSD file and generate JAXB annotated classes for marshalling and unmarshalling the request and response.
- Define the WebService interface and implementation classes.
- Define any interceptor and filter classes if required to intercept the request and responses for implementing the cross-cutting concerns like security validation, logging, auditing, setting up or initializing the locale, etc
- Wire up the classes via Spring and CXF config files. For example, webservices-config.xml and cxf.xml.
- Finally define the CXF servlet and bootstrap the relevant config files via the web.xml file.
Firstly, configure the maven pom.xml file to include the relevant jar files.
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>3.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxrs</artifactId> <version>2.2.3</version> </dependency>
Define the request and response objects with JAXB annotations as our Web service payload is XML, hence it needs to be marshalled (i.e. convert from object to XML) and unmarshalled (XML to object). OrderRequest & OrderResponse classes can be generated from XSD file OrderRequestResponde.xsd shown below.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="OrderResponse"> <xs:sequence> <xs:element name="orderId" type="xs:string" minOccurs="0" /> <xs:element name="responseCode" type="responseCode" minOccurs="0" /> <xs:element name="accountId" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:complexType> <xs:complexType name="OrderRequest"> <xs:sequence> <xs:element name="accountId" type="xs:string" minOccurs="0" /> <xs:element name="quantity" type="xs:int" minOccurs="0" /> </xs:sequence> </xs:complexType> <xs:simpleType name="responseCode"> <xs:restriction base="xs:string"> <xs:enumeration value="SUCCESS" /> <xs:enumeration value="FAILED" /> <xs:enumeration value="REJECTED" /> <xs:enumeration value="UNKNOWN" /> </xs:restriction> </xs:simpleType> </xs:schema>
The .java files can be generated via the xjc command to generate JAXB annotated classes. The OrderRequest.java, OrderResponse.java, ResponseCode.java and ObjectFactory.java files are generated under the package "com.myapp.data.order".
xjc -d "c:\temp" -p "com.myapp.data.order" "C:\temp\xsd\OrderRequestResponde.xsd" -extension
Here are the generated files:
OrderRequest.java
// // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.02.07 at 05:07:31 PM EST // package com.myapp.data.order; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlType; /** * Java class for OrderRequest complex type. * * The following schema fragment specifies the expected content contained within this class. * ** <complexType name="OrderRequest"> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence> * <element name="accountId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> * <element name="quantity" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/> * </sequence> * </restriction> * </complexContent> * </complexType> ** * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "OrderRequest", propOrder = { "accountId", "quantity" }) public class OrderRequest { protected String accountId; protected Integer quantity; /** * Gets the value of the accountId property. * * @return * possible object is * {@link String } * */ public String getAccountId() { return accountId; } /** * Sets the value of the accountId property. * * @param value * allowed object is * {@link String } * */ public void setAccountId(String value) { this.accountId = value; } /** * Gets the value of the quantity property. * * @return * possible object is * {@link Integer } * */ public Integer getQuantity() { return quantity; } /** * Sets the value of the quantity property. * * @param value * allowed object is * {@link Integer } * */ public void setQuantity(Integer value) { this.quantity = value; } }
OrderResponse.java
// // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.02.07 at 05:07:31 PM EST // package com.myapp.data.order; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlType; /** * Java class for OrderResponse complex type. * * The following schema fragment specifies the expected content contained within this class. * ** <complexType name="OrderResponse"> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence> * <element name="orderId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> * <element name="responseCode" type="{}responseCode" minOccurs="0"/> * <element name="accountId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> * </sequence> * </restriction> * </complexContent> * </complexType> ** * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "OrderResponse", propOrder = { "orderId", "responseCode", "accountId" }) public class OrderResponse { protected String orderId; protected ResponseCode responseCode; protected String accountId; /** * Gets the value of the orderId property. * * @return * possible object is * {@link String } * */ public String getOrderId() { return orderId; } /** * Sets the value of the orderId property. * * @param value * allowed object is * {@link String } * */ public void setOrderId(String value) { this.orderId = value; } /** * Gets the value of the responseCode property. * * @return * possible object is * {@link ResponseCode } * */ public ResponseCode getResponseCode() { return responseCode; } /** * Sets the value of the responseCode property. * * @param value * allowed object is * {@link ResponseCode } * */ public void setResponseCode(ResponseCode value) { this.responseCode = value; } /** * Gets the value of the accountId property. * * @return * possible object is * {@link String } * */ public String getAccountId() { return accountId; } /** * Sets the value of the accountId property. * * @param value * allowed object is * {@link String } * */ public void setAccountId(String value) { this.accountId = value; } }
ResponseCode.java
// // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.02.07 at 05:07:31 PM EST // package com.myapp.data.order; import javax.xml.bind.annotation.XmlEnum; import javax.xml.bind.annotation.XmlType; /** * Java class for responseCode. * * The following schema fragment specifies the expected content contained within this class. * ** <simpleType name="responseCode"> * <restriction base="{http://www.w3.org/2001/XMLSchema}string"> * <enumeration value="SUCCESS"/> * <enumeration value="FAILED"/> * <enumeration value="REJECTED"/> * <enumeration value="UNKNOWN"/> * </restriction> * </simpleType> ** */ @XmlType(name = "responseCode") @XmlEnum public enum ResponseCode { SUCCESS, FAILED, REJECTED, UNKNOWN; public String value() { return name(); } public static ResponseCode fromValue(String v) { return valueOf(v); } }
The ObjectFactory.java
// // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.02.07 at 05:07:31 PM EST // package com.myapp.data.order; import javax.xml.bind.annotation.XmlRegistry; /** * This object contains factory methods for each * Java content interface and Java element interface * generated in the com.myapp.data.order package. * An ObjectFactory allows you to programatically * construct new instances of the Java representation * for XML content. The Java representation of XML * content can consist of schema derived interfaces * and classes representing the binding of schema * type definitions, element declarations and model * groups. Factory methods for each of these are * provided in this class. * */ @XmlRegistry public class ObjectFactory { /** * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.myapp.data.order * */ public ObjectFactory() { } /** * Create an instance of {@link OrderResponse } * */ public OrderResponse createOrderResponse() { return new OrderResponse(); } /** * Create an instance of {@link OrderRequest } * */ public OrderRequest createOrderRequest() { return new OrderRequest(); } }
Define the Web service interface ExecutionWebService.java.
package com.myapp.webservice.orderexecutionservices; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import com.myapp.data.order.*; @Path("execution/1.0") public interface ExecutionWebService { // ------------------------- // Create Order // ------------------------- @POST @Path("/order/create") @Consumes("application/xml") @Produces("text/xml") OrderResponse createOrder(OrderRequest orderRequest); // ------------------------- // Amend Order // ------------------------- @POST @Path("/order/amend") @Consumes("application/xml") @Produces("text/xml") OrderResponse amendOrder(OrderRequest orderRequest); //-------------------------- // Cancel Order //-------------------------- @POST @Path("/order/cancel") @Consumes("application/xml") @Produces("text/xml") OrderResponse cancelOrder(OrderRequest orderRequest); }
Define the Web service implementation class ExecutionWebServiceImpl.java. This class makes use of the back-end service class OrderService.java to talk to to the DAO layer, which is not shown here.
package com.myapp.webservice.orderexecutionservices.impl; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.WebApplicationException; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.ws.WebServiceContext; import javax.xml.ws.handler.MessageContext; import com.myapp.data.order.OrderRequest; import com.myapp.data.order.OrderResponse; public class ExecutionWebServiceImpl implements ExecutionWebService { private OrderService orderService; public ExecutionWebServiceImpl() { } public ExecutionWebServiceImpl(OrderService orderService) { this.setOrderService(orderService); } public void setOrderService(OrderService orderService) { this.orderService = orderService; } public OrderService getOrderService() { return orderService; } @Override public OrderResponse createOrder(OrderRequest orderRequest) { OrderResponse response = null; try { //call to back end service response = getOrderService().createOrder(orderRequest); } catch (Exceprion e) { throw new WebApplicationException(e); } return response; } @Override public OrderResponse amendOrder(OrderRequest orderRequest) { OrderResponse response = null; try { response = getOrderService().amendOrder(orderRequest); } catch (Exception e) { throw new WebApplicationException(e); } return response; } @Override public OrderResponse cancelOrder(OrderRequest orderRequest) { OrderResponse response = null; try { response = getOrderService().cancelOrder(orderRequest, null); } catch (Exception e) { throw new WebApplicationException(e); } return response; } }
Now, wire up the above classes using Spring and CXF configuration files.
The webservices-config.xml file.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-http.xml" /> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!-- Configure Execution Web Services Beans --> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <bean id="executionWebService" class="com.myapp.webservice.orderexecutionservices.impl.ExecutionWebServiceImpl"> <constructor-arg ref="orderService" /> </bean> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!-- CONFIGURE ENDPOINTS --> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <jaxrs:server id="executionservices" address="/executionservices/"> <jaxrs:inInterceptors> <ref bean="myAppInInterceptor" /> </jaxrs:inInterceptors> <jaxrs:outInterceptors> <ref bean="myAppOutInterceptor" /> </jaxrs:outInterceptors> <jaxrs:providers> <ref bean="exceptionMapperInterceptor" /> </jaxrs:providers> <jaxrs:serviceBeans> <ref bean="executionWebService" /> </jaxrs:serviceBeans> </jaxrs:server> <!-- define orderService, interceptors etc. left out for brevity --> <!-- This can be defined in other Spring context files as well--> </beans>
The cxf.xml file.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:http="http://cxf.apache.org/transports/http/configuration" xsi:schemaLocation=" http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <http:conduit name="*.http-conduit"> <http:tlsClientParameters secureSocketProtocol="SSL" disableCNCheck="true"/> <http:client AllowChunking="false" ReceiveTimeout="60000"/> </http:conduit> </beans>
Finally, register the CXF servlet and bootstrap the above config files via web.xml file. The web.xml file snippet is shown below.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="services" version="2.5"> <display-name>webservices</display-name> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!-- CONFIGURE SPRING CONTAINER --> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:transactionContext.xml classpath*:daoContext.xml /WEB-INF/webservice-config.xml classpath*:/cxf.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!-- CONFIGURE CXF SERVLET --> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!-- CONFIGURE JNDI RESOURCES --> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <resource-ref> <description>My App Data Source</description> <res-ref-name>jdbc/dataSource/MyDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app>
Now, the sample client that consumes the Web service.
Note that the interface classes like ExecutionWebService, OrederRequest, OrderResponse, etc will be required by both the client (i.e. the Web service consumer) and the service implementation classes like ExecutionWebServiceImpl (i.e. service provider). Hence, the interface classes need to be packaged as separate jar file to be used by both the client and the service implementation.
package com.myapp.webservice.client; import org.apache.cxf.jaxrs.client.Client; import org.apache.cxf.jaxrs.client.JAXRSClientFactory; //...other imports public class ExecutionWebServiceClient { private static final String EXECUTION_SERVICES_CONTEXT_ROOT = "executionservices"; public void consumeRestWebService( ) Throws Exception { ExecutionWebService serviceClient = JAXRSClientFactory.create("http://localhost:8080" + EXECUTION_SERVICES_CONTEXT_ROOT, ExecutionWebService.class); OrderRequest request = constructOrderReqObj(); // not shown OrderResponse response = serviceClient.createOrder(request); //... do something with the response. } }
The URLs that we be used will be like
http://localhost:8080/executionservices/execution/1.0/order/create http://localhost:8080/executionservices/execution/1.0/order/amend http://localhost:8080/executionservices/execution/1.0/order/cancel
That's all to it. You can also test your Web service using the "poster" plugin for Firefox.
The request payload will be something like:
<?xml version="1.0" encoding="UTF-8"?> <OrderRequest> <orderId>orderId</orderId> <responseCode>responseCode</responseCode> <accountId>accountId</accountId> </OrderRequest>
The response payload will be something like
<?xml version="1.0" encoding="UTF-8"?> <OrderResponse> <orderId>orderId</orderId> <responseCode>responseCode</responseCode> <accountId>accountId</accountId> </OrderResponse>
Note: You could generate the payload from the XSD file within eclipse IDE by selecting the schema file and then right clicking to click on Generate --> XML. Make sure you check optional elements to be included. It will also require a root element, henc you need to wrap you r schema with something like
<xs:element name="OrderRequest" > ....... </xs:element>
to generate the request payload and
<xs:element name="OrderResponse" > ....... </xs:element>
to generate the response payload within eclipse IDE.
Other relevant links on Web Services
Web Services Interview Questions and Answers - Overview
Labels: Web services
7 Comments:
As always good questions and better explanation. I must tell that I have benefited earlier from your book and now with your site. great work. By the way I also shared few REST web services questions from interview, guys may find useful.
Javin, I have read some of your blog posts as well. Keep up the good work.
With RESTfull ws, wouldn't you rather write classes representing the data to be transfered via WS (DTO), and use marshalling, unmarshaling instead of defining xsd file(s)?
For marshalling and unmarshalling you need to provide the object to XML mapping. Forexample, via JAXB.
Can rest webservice support multiple interfaces?
I have a below class that implements two interfaces
@path("data")
public testImpl implements ItestA, ItestB{
}
but it finds path to only the first interface.
@path("intA")
public interface ItestA{
@path("in");
public int getInt();
}
@path("StringB")
public interface ItestB{
@path("str")
public String getString();
}
but it always gives value for the first interface that is implemented and not second.
please suggest.
Wonder full blog...
Gave a good information to me on SOAP and RESTfull webservices
Thanks alot
Suppose, I have created a webservice using REST, how can I notify my clients about change in interface? in SOAP we generally do using WSDL file. Is there any such similar concept in REST?
Post a Comment
Subscribe to Post Comments [Atom]
<< Home