Web services are self-contained, modular, distributed, dynamic
applications that can be described, published, located, or invoked over the
network to create products, processes, and supply chains. These applications
can be local, distributed, or web-based. Web services are built on top of open
standards such as TCP/IP, HTTP, Java, HTML, and XML.
A web service is a collection of open protocols and standards used for
exchanging data between applications or systems. Software applications written
in various programming languages and running on various platforms can use web
services to exchange data over computer networks like the Internet in a manner
similar to inter-process communication on a single computer. This
interoperability (e.g., between Java and Python, or Windows and Linux
applications) is due to the use of open standards.
There are two types of
webservices
1. SOAP
2. RestFul
Difference
between SOA and a Web service
SOA is a software design principle and an
architectural pattern for implementing loosely coupled, reusable and coarse
grained services. You can implement SOA using any protocols such as HTTP,
HTTPS, JMS, SMTP, RMI, IIOP (i.e. EJB uses IIOP), and RPC etc. Messages can be
in XML, JSON, TEXT or Data Transfer Objects (DTOs).
Web service is an implementation technology and one of
the ways to implement SOA. You can build SOA based applications without using
Web services – for example by using other traditional technologies like Java
RMI, EJB, JMS based messaging, etc. But what Web services offer is the
standards based and platform-independent service via HTTP, XML, SOAP, WSDL and
UDDI, thus allowing interoperability between heterogeneous technologies such as
J2EE, .NET and any other languages.
Soap
|
Restful
|
The
SOAP WS is transport protocol neutral. Supports multiple protocols like HTTP
, HTTPS, TCP, UDP SMTP, etc
|
The
REST is transport protocol specific. Supports only HTTP or HTTPS protocols
|
The
SOAP WS permits only XML data format. You define operations, which tunnels through the POST.
The focus is on accessing the named operations and exposing the application
logic as a service
|
The
REST permits multiple data formats like XML, JSON data, text, HTML, etc. Any browser can be used because
the REST approach uses the standard GET, PUT, POST, and DELETE Web
operations. The focus is on accessing the named resources and exposing the
data as a service. REST has AJAX support. It can use the XMLHttpRequest
object. Good for stateless CRUD (Create, Read, Update, and Delete)
operations.
GET - read() POST - create() PUT - update() DELETE - delete() |
SOAP
based reads cannot be cached
|
REST
based reads can be cached.
Performs and scales better.
|
The
SOAP WS supports both remote procedure call (i.e. RPC) and message oriented
middle-ware (MOM) integration styles
|
The
Restful Web Service supports only RPC integration style
|
The SOAP
has success or retry logic built in and provides end-to-end reliability even
through SOAP intermediaries
|
REST does
not have a standard messaging system, and expects clients invoking the
service to deal with communication failures by retrying
|
SOAP
WS supports both SSL security and WS-security, which adds some enterprise security features like
maintaining security right up to the point where it is needed, maintaining
identities through intermediaries and not just point to point SSL only,
securing different parts of the message with different security algorithms,
etc
|
The
REST supports only point-to-point SSL security. The SSL encrypts the whole message, whether all of it is
sensitive or not.
|
The
SOAP has comprehensive support for both ACID based transaction
management for short-lived transactions and compensation based
transaction management for long-running transactions. It also supports two-phase
commit across distributed resources
|
The
REST supports transactions, but it is neither ACID compliant nor can
provide two phase commits across distributed transactional resources as it is
limited by its HTTP protocol
|
Defines
the contract via WSDL.
|
Traditionally,
the big drawback of REST was the lack of contract for the web service
|
Best Practice (BP): In general, a REST
based web service is preferred due to its simplicity, performance,
scalability, and support for multiple data formats. SOAP is favored where
service requires comprehensive support for security, transactional
reliability and stricter contract.
|
Components of SOAP Web Services
The
basic web services platform is XML + HTTP. All the standard web services work
using the following components −
- SOAP (Simple
Object Access Protocol)
- UDDI
(Universal Description, Discovery and Integration)
- WSDL (Web
Services Description Language)
Structure of a WSDL Document
Web Services Description Language (WSDL)
is an XML grammar for describing network services as collections of
communication endpoints capable of exchanging messages. The diagram below
illustrates the elements that are present in a WSDL document, and indicates
their relationships.
· WSDL breaks down Web services into three specific, identifiable
elements that can be combined or reused once defined.
· Three major elements of WSDL that can be defined separately and
they are:
Types
Operations
Binding
· A WSDL document has various elements, but they are contained
within these three main elements, which can be developed as separate documents
and then they can be combined or reused to form complete WSDL files.
· Following are the elements of WSDL document. Within these elements
are further sub elements, or parts:
· Definition: element must be the root element of all WSDL documents. It defines
the name of the web service, declares multiple namespaces used throughout the
remainder of the document, and contains all the service elements described
here.
· Data types: the data types - in the form of XML schemas or possibly some other
mechanism - to be used in the messages
· Message: an abstract definition of the data, in the form of a message
presented either as an entire document or as arguments to be mapped to a method
invocation.
· Operation: the abstract definition of the operation for a message, such as
naming a method, message queue, or business process, that will accept and
process the message
· Port type : an abstract set of operations mapped to one or more end points,
defining the collection of operations for a binding; the collection of
operations, because it is abstract, can be mapped to multiple transports
through various bindings.
· Binding: the concrete protocol and data formats for the operations and
messages defined for a particular port type.
· Port: a combination of a binding and a network address, providing the
target address of the service communication.
· Service: a collection of related end points encompassing the service
definitions in the file; the services map the binding to the port and include
any extensibility definitions.
· In addition to these major elements, the WSDL specification also
defines the following utility elements:
· Documentation: element is used to provide human-readable documentation and can be
included inside any other WSDL element.
· Import: element is used to import other WSDL documents or XML Schemas.
· NOTE: WSDL parts usually are generated automatically using Web
services-aware tools.
The main structure of a WSDL document
looks like this:
<definitions>
<types>
definition of data types........
</types>
<message>
definition of a message....
</message>
<portType>
<operation>
definition
of a operation i/p and o/p.......
</operation>
</portType>
<binding>
definition of a binding....
</binding>
<service>
definition of a service.... (URI)
</service>
</definitions>
|
<definitions name="HelloService"
targetNamespace="http://www.examples.com/wsdl/HelloService.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.examples.com/wsdl/HelloService.wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<message name="SayHelloRequest">
<part name="firstName"
type="xsd:string"/>
</message>
<message name="SayHelloResponse">
<part name="greeting"
type="xsd:string"/>
</message>
<portType name="Hello_PortType">
<operation
name="sayHello">
<input
message="tns:SayHelloRequest"/>
<output message="tns:SayHelloResponse"/>
</operation>
</portType>
<binding name="Hello_Binding"
type="tns:Hello_PortType">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="sayHello">
<soap:operation
soapAction="sayHello"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:examples:helloservice"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:examples:helloservice"
use="encoded"/>
</output>
</operation>
</binding>
<service name="Hello_Service">
<documentation>WSDL File for
HelloService</documentation>
<port
binding="tns:Hello_Binding" name="Hello_Port">
<soap:address
location="http://www.examples.com/SayHello/">
</port>
</service>
</definitions>
|
Difference between RPC and Document web services
There are many differences between RPC and Document web services.
The important differences between RPC and Document are given below:
RPC Style
1) RPC style web services use method name and parameters to
generate XML structure.
2) The generated WSDL is difficult to be validated against
schema.
3) In RPC style, SOAP message is sent as many elements.
4) RPC style message is tightly coupled.
5) In RPC style, SOAP message keeps the operation name.
6) In RPC style, parameters are sent as discrete values.
Let's see the RPC style generated WSDL file.
WSDL
file: In WSDL file, it doesn't
specify the types details.
1.
<message name="getHelloWorldAsString">
2.
<part name="arg0" type="xsd:string"/>
3.
</message>
4.
<message name="getHelloWorldAsStringResponse">
5.
<part name="return" type="xsd:string"/>
6. </message>
For soap:body, it
defines use and namespace attributes.
1.
<binding name="HelloWorldImplPortBinding" type="tns:HelloWorld">
2.
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
3.
<operation name="getHelloWorldAsString">
4.
<soap:operation soapAction=""/>
5.
<input>
6.
<soap:body use="literal" namespace="http://abc.com/"/>
7.
</input>
8.
<output>
9.
<soap:body use="literal" namespace="http://abc.com/"/>
10.
</output>
11.
</operation>
12.
</binding>
|
Document Style
1) Document style web services can be validated against
predefined schema.
2) In document style, SOAP message is sent as a single document.
3) Document style message is loosely coupled.
4) In Document style, SOAP message loses the operation name.
5) In Document style, parameters are sent in XML format.
Let's see the Document style generated WSDL file.
WSDL file:In
WSDL file, it specifies type’s details having namespace and
schemaLocation.
1.
<types>
2.
<xsd:schema>
3.
<xsd:import namespace="http://abc.com/" schemaLocation="http://abc:7779/ws/hello?xsd=1"/>
4.
</xsd:schema>
5.
</types>
For
message part, it defines name and element attributes.
1.
<message name="getHelloWorldAsString">
2.
<part name="parameters" element="tns:getHelloWorldAsString"/>
3.
</message>
4.
<message name="getHelloWorldAsStringResponse">
5.
<part name="parameters" element="tns:getHelloWorldAsStringResponse"/>
6.
</message>
For
soap:body, it defines use attribute only not namespace.
1.
<binding name="HelloWorldImplPortBinding" type="tns:HelloWorld">
2.
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
3.
<operation name="getHelloWorldAsString">
4.
<soap:operation soapAction=""/>
5.
<input>
6.
<soap:body use="literal"/>
7.
</input>
8.
<output>
9.
<soap:body use="literal"/>
10.
</output>
11.
</operation>
12.
</binding>
|
Contract-first (top-down) and Contract-last (bottom-up)
approach of developing SOAP web services
In top-down approach first WSDL document is created
and then Java classes are developed based on WSDL contract, so if WSDL contract
changes you got to change your Java classes while in case of bottom up approach
of web service development you first create Java code and then use annotations
like @WebService to specify contract or interface and WSDL field will be
automatically generated from your build.
Contract-first Web service (top-down approach)
PROS:
Clients are decoupled from the server, hence the
implementation logic can be revised on the server without affecting the
clients.
Developers can work simultaneously on client and
server side based on the contract both agreed on.
You have full control over how the request and
response messages are constructed -- for example, should "status" go
as an element or as an attribute? The contract clearly defines it. You can
change OXM (i.e. Object to XML Mapping) libraries without having to worry if
the "status" would be generated as "attribute" instead of
an element. Potentially, even Web service frameworks and tool kits can be
changed as well from say Apache Axis to Apache CXF, etc
CONS:
More upfront work is involved in setting up the XSDs
and WSDLs. There are tools like XML Spy, Oxygen XML, etc to make things easier.
Developers need to learn XSDs and WSDLs in addition to
just knowing Java.
Contract-last Web service (bottom-up)
PROS:
Developers don't have to learn anything related to
XSDs, WSDLs, and SOAP. The services are created quickly by exposing the
existing service logic with frameworks/tool sets.
The learning curve and development time can be smaller
compared to the Contract-first Web service.
CONS:
The development time can be shorter to initially
develop it, but what about the ongoing maintenance and extension time if the
contract changes or new elements need to be added? In this approach, since the
clients and servers are more tightly coupled, the future changes may break the
client contract and affect all clients or require the services to be properly
versioned and managed.
In this
approach, The XML payloads cannot be controlled. This means changing your OXM
libraries could cause something that used to be an element to become an
attribute with the change of the OXM.
RESTful web services
REST stands for REpresentational State Transfer (REST)
which enforces a stateless client server design where web services are treated
as resource and can be accessed and identified by their URL.
Web services written by apply REST Architectural
concept are called RESTful web services which focus on System resources and how
state of Resource should be transferred over http/https protocol to a different
clients written in different languages. In RESTful web services http methods
like GET, PUT, POST and DELETE can
be used to perform CRUD operations.
Resource in REST framework
A resource is a unique URL with representation of an object
which we can get contents via GET and modify via PUT, POST and DELETE.
HTTP methods
supported by REST
·
GET: It
requests a resource at the request URL. It should not contain a request body as
it will be discarded. May be it can be cached locally or on the server.
·
POST: It submits
information to the service for processing; it should typically return the
modified or new resource
·
PUT: At
the request URL it update the resource and it is idempotent
·
DELETE: At
the request URL it removes the resource
·
OPTIONS: It
indicates which techniques are supported
·
HEAD: About
the request URL it returns meta information
What
happens if RestFull resources are accessed by multiple clients ? do you need to
make it thread-safe?
Since a new Resource instance is created for every
incoming Request there is no need to make it thread-safe or add
synchronization. multiple client can safely access RestFull resources
concurrently.
Jersey
framework
Jersey is open source framework for developing RESTful Web
Services in Java that provides support for JAX-RS APIs and serves as a JAX-RS
(JSR 311 & JSR 339) Reference Implementation. It has advantages such
as
§ contains
support for Web Application Description Language (WADL);
§ contains
Jersey Test Framework which lets run and test Jersey REST services inside
JUnit;
§ Supports
for the REST MVC pattern, which would allow to return a View from Jersey
services rather than just data.
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.FormParam;
import javax.ws.rs.core.Response;
@Path("/persons")
public
class PersonRestService {
/*
@PathParam
annotation injects the value of URI parameter that defined in @Path
expression
On
calling URI: “/persons/1” result: getPersonById is called, id : 1
*/
@GET
@Path("{id}")
public
Response getPersonById(@PathParam("id") String id) {
return Response.status(200).entity("getPersonById
is called, id : " + id).build();
}
/*
@QueryParam
annotation injects URI query parameter into Java method
“/persons/query?from=10&to=20&orderBy=age&orderBy=name”
result: getPersons is called, from : 10, to : 20, orderBy[age, name]
*/
@GET
@Path("/query")
public
Response getPersons(
@QueryParam("from")
int from,
@QueryParam("to")
int to,
@QueryParam("orderBy")
List<String> orderBy) {
return Response
.status(200)
.entity("getPersons is called, from :
" + from + ", to : " + to
+ ",
orderBy" + orderBy.toString()).build();
}
/*
@FormParam
bind HTML form parameters value to a Java method
*/
@POST
@Path("/add")
public
Response addPerson(
@FormParam("name")
String name,
@FormParam("age")
int age) {
return Response.status(200)
.entity("addPerson
is called, name : " + name + ", age : " + age)
.build();
}
}
|
@MatrixParam are a set of “name=value” in URI path.
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
@Path("/books")
public
class BookService {
@GET
@Path("{year}")
public
Response getBooks(@PathParam("year") String year,
@MatrixParam("author")
String author,
@MatrixParam("country")
String country) {
return Response
.status(200)
.entity("getBooks
is called, year : " + year
+ ",
author : " + author + ", country : " + country)
.build();
}
}
|
On calling URI: “/books/2015” result: getBooks is called, year : 2015, author
: null, country : null
On calling URI: “/books/2015;author= doyle;country=scotland ” result: getBooks is called, year : 2015, author : doyle, country : scotland
download img/file in JAX-RS
§ put
@Produces(“?”) on service method, with a Response return type. Instead “?”
write a type text/plain, image/png, etc.
§
set “Content-Disposition” in Response header to tell browser pop
up a download box for user to download.
import java.io.File;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
@Path("/image")
public class ImageService {
private static final String FILE_PATH = "c:\\my.png";
@GET
@Path("/get")
@Produces("image/png")
public Response getFile() {
File file = new File(FILE_PATH);
ResponseBuilder response = Response.ok((Object)
file);
response.header("Content-Disposition",
"attachment; filename=image_from_server.png");
return response.build();
}
}
|
HTTP request
header in JAX-RS (2 ways)
§ inject
directly with @HeaderParam;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.core.Response;
@Path("/persons")
public class PersonService {
@GET
@Path("/get")
public Response getPerson(
@HeaderParam("person-agent")
String personAgent) {
return Response.status(200)
.entity("getPerson is called, personAgent : " +
personAgent)
.build();
}
}
|
On calling URI: “/persons/get” result: getPerson is called, personAgent :
Mozilla/5.0(Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0
§
pragmatically via @Context.
import
javax.ws.rs.GET;
import
javax.ws.rs.Path;
import
javax.ws.rs.core.Context;
import
javax.ws.rs.core.HttpHeaders;
import
javax.ws.rs.core.Response;
@Path("/persons")
public
class PersonService {
@GET
@Path("/get")
public
Response getPerson(@Context HttpHeaders headers) {
String
personAgent = headers.getRequestHeader("person-agent").get(0);
return Response.status(200)
.entity("getPerson
is called, personAgent : " + personAgent)
.build();
}
}
|
On calling URI: “/persons/get” result: getPerson is called, personAgent :
Mozilla/5.0(Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0
JAX-WS
and JAX-RS
Both JAX-WS and JAX-RS are libraries (APIs) for doing communication
in various ways in Java. JAX-WS is a library that can be used to do SOAP
communication in JAVA, and JAX-RS lets you do the REST communication in JAVA
Spring
RESTFul webservice
Using
spring framework we can develop the RESTFul webservices, the all other concepts
remains the same.
Example
import
java.util.ArrayList;
import
java.util.Date;
import
java.util.HashMap;
import
java.util.List;
import
java.util.Map;
import
java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.web.bind.annotation.PathVariable;
import
org.springframework.web.bind.annotation.RequestBody;
import
org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import
org.springframework.web.bind.annotation.ResponseBody;
import
org.springframework.web.bind.annotation.RestController;
import
com.sathish.tutorials.springboot.restapi.dto.Employee;
import com.sathish.tutorials.springboot.restapi.service.EmployeeService;
/**
*
Handles requests for the Employee service.
*/
@RestController
public class EmployeeController {
//
Map to store employees, ideally it should come from database
Map<Integer,
Employee> empData = new HashMap<Integer, Employee>();
@Autowired
private
EmployeeService employeeService;
//
URL http://localhost:8080/rest/emp/default
@RequestMapping(value
= "/rest/emp/default", method = RequestMethod.GET, produces = "application/json")
public
@ResponseBody Employee getDefaultEmployee() {
Employee
emp = new Employee();
emp
= employeeService.getDefaultEmployeeService();
empData.put(9999,
emp);
return
emp;
}
//
URL http://localhost:8080/rest/emp/9999
@RequestMapping(value
= "/rest/emp/{id}", method = RequestMethod.GET, produces =
"application/json")
public
@ResponseBody Employee getEmployee(@PathVariable("id") int empId) {
System.out.println("Start
getEmployee. ID=" + empId);
return
empData.get(empId);
}
//
URL http://localhost:8080//rest/emp/create
//
request {"id":1,"name":"Sathish
//
Kariyanna","createdDate":"2018-06-24T20:25:58.096+0000"}
@RequestMapping(value
= "/rest/emp/create", method = RequestMethod.POST, produces =
"application/json")
public
@ResponseBody Employee createEmployee(@RequestBody Employee emp) {
System.out.println("Start
createEmployee.");
emp.setCreatedDate(new
Date());
empData.put(emp.getId(),
emp);
return
emp;
}
//
URL http://localhost:8080/rest/emps
@RequestMapping(value
= "/rest/emps", method = RequestMethod.GET, produces =
"application/json")
public
@ResponseBody List<Employee> getAllEmployees() {
System.out.println("Start
getAllEmployees.");
List<Employee>
emps = new ArrayList<Employee>();
Set<Integer>
empIdKeys = empData.keySet();
for
(Integer i : empIdKeys) {
emps.add(empData.get(i));
}
return
emps;
}
//
URL http://localhost:8080//rest/emp/update
//
request
//
{"id":1,"name":"Sathish","createdDate":"2018-06-25T20:25:58.096+0000"}
@RequestMapping(value
= "/rest/emp/update", method = RequestMethod.PUT, produces =
"application/json")
public
@ResponseBody Employee updateEmployee(@RequestBody Employee emp) {
System.out.println("Start
updateEmployee.");
empData.put(emp.getId(),
emp);
return
emp;
}
//
URL http://localhost:8080//rest/emp/delete/1
@RequestMapping(value
= "/rest/emp/delete/{id}", method = RequestMethod.DELETE)
public
@ResponseBody Employee deleteEmployee(@PathVariable("id") int
empId) {
System.out.println("Start
delete Employee.");
Employee
emp = empData.get(empId);
empData.remove(empId);
return
emp;
}
}
|
@RestController annotation was introduced in Spring 4.0 to simplify
the creation of RESTful web services. It’s a convenience annotation
that combines @Controller and @ResponseBody –
which eliminates the need to annotate every request handling method of the controller class with the @ResponseBody annotation.
(we do not need to use @ResponseBody)
@RequestMapping annotation is
used to map the request URI to the handler method.
@ResponseBody annotation is
used to map the response object in the response body. Once the response object
is returned by the handler method, MappingJackson2HttpMessageConverter kicks in
and convert it to JSON response.
@PathVariable annotation is the
easy way to extract the data from the rest URI and map it to the method
argument.
@RequestBody annotation is used
to map the request body JSON data into the Employee object, again this is done
by the MappingJackson2HttpMessageConverter mapping.
URI Versioning
Request Parameter versioning
(Custom) Headers versioning
Media type versioning (“content negotiation” or “accept header”)
Restful
Web Services Versioning
· The
best approach to versioning is NOT to do it. Yeah, that’s right. Do not version
as long as versioning is not needed. However there are a number of situations
where versioning is needed.
· Build
your services to backward compatible so that you can avoid versioning as much
as possible.
package
com.sathish.springboot.restapi.controller;
import
org.springframework.web.bind.annotation.RequestMapping;
import
org.springframework.web.bind.annotation.RequestMethod;
import
org.springframework.web.bind.annotation.RestController;
import
com.sathish.springboot.restapi.dto.Name;
import
com.sathish.springboot.restapi.dto.PersonV1;
import
com.sathish.springboot.restapi.dto.PersonV2;
@RestController
publicclass
PersonVersioningController {
// URI Versioning
// URL
http://localhost:8080/rest/v1/person
@RequestMapping(value
= "/rest/v1/person", method = RequestMethod.GET)
public
PersonV1 PersonV1() {
returnnew
PersonV1("Sathish Kariyanna");
}
// URI Versioning
// URL
http://localhost:8080/rest/v2/person
@RequestMapping(value
= "/rest/v2/person", method = RequestMethod.GET)
public
PersonV2 PersonV2() {
returnnew
PersonV2(new Name("Sathish", "Kariyanna"));
}
//Request
Parameter versioning
// URL
http://localhost:8080/rest/person/param?version=1
@RequestMapping(value
= "/rest/person/param", method = RequestMethod.GET,
params = "version=1")
public
PersonV1 paramV1() {
returnnew
PersonV1("Sathish Kariyanna");
}
//Request
Parameter versioning
// URL
http://localhost:8080/rest/person/param?version=2
@RequestMapping(value
= "/rest/person/param", method = RequestMethod.GET,
params = "version=2")
public
PersonV2 paramV2() {
returnnew
PersonV2(new Name("Sathish", "Kariyanna"));
}
//
Headers(Custom) versioning
// URL
http://localhost:8080/rest/person/header and add header [X-API-VERSION=1]
@RequestMapping(value
= "/rest/person/header", method = RequestMethod.GET,
headers = "X-API-VERSION=1")
public
PersonV1 headerV1() {
returnnew
PersonV1("Sathish Kariyanna");
}
//
Headers(Custom) versioning
// URL
http://localhost:8080/rest/person/header and add header [X-API-VERSION=2]
@RequestMapping(value
= "/rest/person/header", method = RequestMethod.GET,
headers = "X-API-VERSION=2")
public
PersonV2 headerV2() {
returnnew
PersonV2(new Name("Sathish", "Kariyanna"));
}
//Media type versioning
(“content negotiation” or “accept header”)
// URL
http://localhost:8080/rest/person/produces and add
headers[Accept=application/vnd.company.app-v1+json]
@RequestMapping(value
= "/rest/person/produces", method = RequestMethod.GET,
produces = "application/vnd.company.app-v1+json")
public
PersonV1 producesV1() {
returnnew
PersonV1("Sathish Kariyanna");
}
//Media type versioning
(“content negotiation” or “accept header”)
// URL
http://localhost:8080/rest/person/produces and add headers[Accept=application/vnd.company.app-v2+json]
@RequestMapping(value
= "/rest/person/produces", method = RequestMethod.GET,
produces = "application/vnd.company.app-v2+json")
public
PersonV2 producesV2() {
returnnew
PersonV2(new Name("Sathish", "Kariyanna"));
}
}
URI Versioning
Basic approach to
versioning is to create a completely different URI for the new service. Example
implementation is shown in the example code.
Example URL’s
http://localhost:8080/rest/v1/person
http://localhost:8080/rest/v2/person
Request Parameter versioning
In request parameter
versioning the version number is passed URI as the request parameter.
Example URL’s
·
http://localhost:8080/rest/person/param?version=1
·
http://localhost:8080/rest/person/param?version=2
(Custom) Headers versioning
The third approach
to versioning is to use a Request Header, pass the version number in the header.
Example URL’s
·
http://localhost:8080/rest/person/header
o headers
[X-API-VERSION=1]
·
http://localhost:8080/rest/person/header
o headers
[X-API-VERSION=2]
Media type versioning (“content negotiation” or “accept header”)
The fourth
versioning approach is to use the Accept Header in the request.
Examples
·
http://localhost:8080/rest/person/produces
o headers[Accept=application/vnd.company.app-v1+json]
·
http://localhost:8080/rest/person/produces
o headers[Accept=application/vnd.company.app-v2+json]
Writing Unit Test for the Get/POST Rest Service
When we are unit
testing a rest service, we would want to launch only the specific controller
and the related MVC Components. WebMvcTest annotation is used for unit testing
Spring MVC application. This can be used when a test focuses only Spring MVC
components. Using this annotation will disable full auto-configuration and only
apply configuration relevant to MVC tests.
@RunWith(SpringRunner.class)
@WebMvcTest(value = EmployeeController.class, secure = false)
publicclass
EmployeeControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private EmployeeService employeeService;
Employee mockEmployee = new Employee(9999, "default");
@Test
publicvoid getDefaultEmployeeTest() throws Exception {
System.out.println("********************TEST*******************");
Mockito.when(employeeService.getDefaultEmployeeService())
.thenReturn(mockEmployee);
RequestBuilder requestBuilder =
MockMvcRequestBuilders.get("/rest/emp/default")
.accept(MediaType.APPLICATION_JSON);
MvcResult result =
mockMvc.perform(requestBuilder).andReturn();
System.out.println("Response
: " + result.getResponse().getContentAsString());
String expected =
"{id:9999,name:default}";
JSONAssert.assertEquals(expected,
result.getResponse().getContentAsString(), false);
}
}
·
@RunWith(SpringRunner.class) : SpringRunner is short hand for SpringJUnit4ClassRunner which
extends BlockJUnit4ClassRunner providing the functionality to launch a Spring
TestContext Framework.
·
@WebMvcTest(value = EmployeeController.class,
secure = false): WebMvcTest
annotation is used for unit testing Spring MVC application. This can be used
when a test focuses only Spring MVC components. In this test, we want to launch
only EmployeeController. All other controllers and mappings will not be
launched when this unit test is executed.
·
@Autowired private MockMvc mockMvc: MockMvc is the main entry point for server-side Spring MVC
test support. It allows us to execute requests against the test context.
·
@MockBean private EmployeeService
employeeService: MockBean is used
to add mocks to a Spring ApplicationContext. A mock of employeeService is
created and auto-wired into the EmployeeController.
·
Mockito.when(employeeService.getDefaultEmployeeService()).thenReturn(mockEmployee): Mocking the method getDefaultEmployeeService to return the
specific mockEmployee when invoked.
·
MockMvcRequestBuilders.get("/rest/emp/default").accept(MediaType.APPLICATION_JSON): Creating a Request builder to be able to execute a get request
to uri “/rest/emp/default” with accept header as “application/json”
·
mockMvc.perform(requestBuilder).andReturn(): mockMvc is used to perform the request and return the response
back.
·
JSONAssert.assertEquals(expected,
result.getResponse().getContentAsString(), false):
We are using org.skyscreamer.jsonassert.JSONAssert. This allows us to do
partial asserts against a JSON String. We are passing strict as false since we
do not want to check for all fields in the response.
·
MockMvcRequestBuilders.post(“/rest/emp/create").accept(MediaType.APPLICATION_JSON): Create a post request with an accept header for application\json
·
content(exampleCourseJson).contentType(MediaType.APPLICATION_JSON): Use the specified content as body of the request and set
content type header.
·
assertEquals(HttpStatus.CREATED.value(),
response.getStatus()): Assert that the
return status is CREATED.
· response.getHeader(HttpHeaders.LOCATION): Get the location from response
header and later assert that it contains the URI of the created resource.
Important constraints for a RESTful
Web Service
The five important constraints
for RESTful Web Service are
·
Client - Server : There should be a service
producer and a service consumer.
·
The interface (URL) is uniform and exposing
resources. Interface uses nouns (not actions)
·
The service is stateless. Even if the service
is called 10 times, the result must be the same.
·
The service result should be Cacheable. HTTP
cache, for example.
·
Service should assume a Layered architecture.
Client should not assume direct connection to server - it might be getting info
from a middle layer - cache.
Best practices in designing RESTful
APIs
·
While designing any API,
the most important thing is to think about the api consumer i.e. the client who
is going to use the service. What are his needs? Does the service uri make
sense to him? Does the request, response format make sense to him?
·
In Rest, we think Nouns
(resources) and NOT Verbs (NOT actions). So, URI’s should represent resources.
URI’s should be hierarchical and as self-descriptive as possible. Prefer
plurals.
·
Always use HTTP Methods.
Core
components of a HTTP Request
A HTTP Request has five major parts −
·
Verb − Indicate HTTP methods such as GET, POST, DELETE, PUT etc.
·
URI − Uniform Resource Identifier (URI) to identify the
resource on server.
·
HTTP Version − Indicate HTTP version, for example HTTP v1.1 .
·
Request Header − Contains metadata for the HTTP Request message as
key-value pairs. For example, client (or browser) type, format supported by
client, format of message body, cache settings etc.
·
Request Body − Message content or Resource representation.
Core components of a HTTP response
A HTTP Response has four major parts −
·
Status/Response
Code − Indicate Server status for the requested resource. For
example 404 means resource not found and 200 means response is ok.
·
HTTP Version − Indicate HTTP version, for example HTTP v1.1 .
·
Response Header − Contains metadata for the HTTP Response message as
key-value pairs. For example, content length, content type, response date,
server type etc.
·
Response Body − Response message content or Resource representation.
Format
of a URI in REST architecture and best practices to create a standard
URI
A URI is of following format −
<protocol>://<service-name>/<ResourceType>/<ResourceID>
Following are important points to be considered while
designing a URI −
·
Use Plural Noun − Use plural noun to define resources. For example, we've
used users to identify users as a resource.
·
Avoid using spaces − Use underscore(_) or hyphen(-) when using a long resource
name, for example, use authorized_users instead of authorized%20users.
·
Use lowercase
letters − Although URI is case-insensitive, it is good practice to
keep url in lower case letters only.
·
Maintain Backward
Compatibility − As Web Service is
a public service, a URI once made public should always be available. In case,
URI gets updated, redirect the older URI to new URI using HTTP Status code,
300.
·
Use HTTP Verb − Always use HTTP Verb like GET, PUT, and DELETE to do the
operations on the resource. It is not good to use operations names in URI.
Some of the HTTP states codes:
· 1xx Informational
·
100 Continue
2xx
Success
·
200 OK, shows success.
·
201 Created, when a resource is successful created using POST or
PUT request.
·
204 No Content, when response body is empty for example, a DELETE request.
3xx
Redirection
·
302 Found
·
304 Not Modified, used to reduce network bandwidth usage in case of
conditional GET requests. Response body should be empty
·
307 Temporary Redirect
·
308 Permanent Redirect
4xx
Client Error
·
400 Bad Request, , states that invalid input is provided e.g.
validation error, missing data.
·
401 Unauthorized, the
request has not been applied because it lacks valid authentication credentials
for the target resource.
·
403 Forbidden, states that user is not having access to method being used for example, delete access
without admin rights.
·
404 Not Found, states that method is not available.
·
405 Method Not Allowed
5xx
Server Error
·
500 Internal Server
Error, states that server has thrown some
exception while executing the method.
·
502 Bad Gateway
·
503 Service Unavailable
·
504 Gateway Timeout
·
No comments:
Post a Comment