RESTful web services are defined as JSR 311, and the complete specification can be downloaded from http://jcp.org/aboutJava/communityprocess/mrel/jsr311/index.html.
REST is an architectural style of services that utilizes web standards. Web services designed using REST are called RESTful web services. The main principles of RESTful web services are:
Everything can be identified as a resource and each resource is uniquely identifiable using a URI.
A resource can be represented in multiple formats, defined by a media type. The media type will provide enough information on how the requested format needs to be generated. Standard methods are defined for the client and server to negotiate on the content type of the resource.
Use standard HTTP methods to interact with the resource: GET to retrieve a resource, POST to create a resource, PUT to update a resource, and DELETE to remove a resource.
Communication between the client and the endpoint is stateless. All the associated state required by the server is passed by the client in each invocation.
Java API for RESTful web services (JAX-RS) defines a standard annotation-driven API that helps developers build a RESTful web service in Java. The standard principles of REST, such as identifying a resource as a URI, a well-defined set of methods to access the resource, and multiple representation formats of a resource, can be easily marked in a POJO using annotations.
A simple RESTful web service can be defined using @Path
:
@Path("orders") public class Orders { @GET public List<Order> getAll() { //. . . } @GET @Path("{oid}") public Order getOrder(@PathParam("oid")int id) { //. . . } } @XmlRootElement public class Order { int id; //. . . }
In this code:
Orders
is a POJO class and is published as a
RESTful resource at orders
path by adding the class-level
@Path
annotation.
The Order
class is marked with the
@XmlRootElement
annotation, allowing a conversion between Java and XML.
The getAll
resource method, providing a list of all
orders, is invoked when this resource is accessed using the HTTP GET
method; this is identified by specifying the @GET
annotation on the
method.
The @Path
annotation on the getOrder
resource method marks it as a subresource and accessible at
orders/{oid}
.
The curly braces around oid
identifies it as a
template parameter, and binds its value at runtime to the
id
parameter of the getOrder
resource
method.
The @PathParam
can also be used to bind template parameters to a resource
class field as well.
Typically, a RESTful resource is bundled in a
.war file along with other classes and resources. The Application
class and
@ApplicationPath
annotation is used to specify the base path for all the RESTful
resources in the packaged archive. The Application
class also
provides additional metadata about the application.
Let’s say this POJO is packaged in the
store.war file, deployed at
localhost:8080
, and the Application
class is
defined:
@ApplicationPath("webresources") public class ApplicationConfig extends Application { }
A list of all the orders is accessible by issuing a GET request to:
http://localhost:8080/store/webresources/orders
A specific order can be obtained by issuing a GET request to:
http://localhost:8080/store/webresources/orders/1
Here, the value 1
will be passed to
getOrder
’s method parameter id
. The resource
method will locate the order with the correct order number and return back
the Order
class. Having @XmlRootElement
annotation ensures that an XML representation of the resource is
returned back.
A URI may pass HTTP query parameters using name/value pairs. These
can be mapped to resource method parameters or fields using
@QueryParam
annotation. If the resource method getAll
is updated such
that the returned results start from a specific order number, the number
of orders returned can also be specified:
public List<Order> getAll(@QueryParam("start")int from, @QueryParam("page")int page) { //. . . }
And the resource is accessed as:
http://localhost:8080/store/webresources/orders? start=10&page=20
Then 10
is mapped to the from
parameter
and 20
is mapped to the page
parameter.
JAX-RS provides support for binding standard HTTP GET, POST, PUT, DELETE, HEAD, and OPTIONS methods using the corresponding annotations described in Table 9-1.
Table 9-1. HTTP methods supported by JAX-RS
HTTP method | JAX-RS annotation |
---|---|
GET | @GET |
POST | @POST |
PUT | @PUT |
DELETE | @DELETE |
HEAD | @HEAD |
OPTIONS | @OPTIONS |
Let’s take a look at how @POST
is used. Consider the
following HTML form, which takes the order identifier and customer name
and creates an order by posting the form to webresources
/orders/create
:
<form method="post" action="webresources/orders/create"> Order Number: <input type="text" name="id"/><br/> Customer Name: <input type="text" name="name"/><br/> <input type="submit" value="Create Order"/> </form>
The updated resource definition uses the following annotations:
@POST @Path("create") @Consumes("application/x-www-form-urlencoded") public Order createOrder(@FormParam("id")int id, @FormParam("name")String name) { Order order = new Order(); order.setId(id); order.setName(name); return order; }
The @FormParam
annotation binds the value of an HTML form parameter to a resource
method parameter or a field. The name
attribute in the HTML
form and the value of the @FormParam
annotation are
exactly the same to ensure the binding. Clicking the submit button in this
form will return the XML representation of the created Order
.
A Response
object may be used to create a custom response.
The following code shows how @PUT
is used:
@PUT @Path("{id}") @Consumes("*/xml") public Order putXml(@PathParam("id")int id, String content) { Order order = findOrder(id); // update order from "content" . . . return order; }
The resource method is marked as a subresource and {id}
is bound to the resource method parameter id
. The contents of
the body can be any XML media type as defined by @Consumes
and are bound to the content
method parameter. A
PUT request to this resource may be issued as:
curl -i -X PUT -d "New Order" http://localhost:8080/store/webresources/orders/1
The content
method parameter will have the value
New Order
.
Similarly, an @DELETE
resource method can be defined:
@DELETE @Path("{id}") public void putXml(@PathParam("id")int id) { Order order = findOrder(id); // delete order }
The resource method is marked as a subresource and {id}
is bound to the resource method parameter id
. A DELETE
request to this resource may be issued as:
curl -i -X DELETE http://localhost:8080/store/webresources/orders/1
The content
method parameter will have the value
New Order
.
The HEAD and OPTIONS methods receive automated support from JAX-RS.
The HTTP HEAD method is identical to GET except that no response
body is returned. This method is typically used to obtain meta-information
about the resource without requesting the body. The set of HTTP headers in
response to a HEAD request is identical to the information sent in
response to a GET request. If no method is marked with @HEAD
,
an equivalent @GET
method is called and the response body is
discarded. The @HEAD
annotation is used to mark a method
serving HEAD requests:
@HEAD @Path("{id}") public void headOrder(@PathParam("id")int id) { System.out.println("HEAD"); }
This method is often used for testing hypertext links for validity, accessibility, and recent modification. A HEAD request to this resource may be issued as:
curl -i -X HEAD http://localhost:8080/store/webresources/orders/1
The HTTP response header contains HTTP/1.1 204 No
Content
and no content body.
The HTTP OPTIONS method requests for communication options available
on the request/response identified by the URI. If no method is designated
with @OPTIONS
, the JAX-RS runtime generates an automatic
response using the annotations on the matching resource class and methods.
The default response typically works in most cases. @OPTIONS
may be used to customize the response to the OPTIONS
request:
@OPTIONS @Path("{id}") public Response options() { // create a custom Response and return }
An OPTIONS request to this resource may be issued as:
curl -i -X OPTIONS http://localhost:8080/store/webresources/orders/1
The HTTP Allow
response header provides information about the HTTP operations
permitted. The Content-Type
header is used to specify the media type of the body, if any is
included.
In addition to the standard set of methods supported with
corresponding annotations, HttpMethod
may be used to build
extensions such as WebDAV.
By default, a RESTful resource is published or consumed with */*
MIME type. A RESTful resource can
restrict the media types supported by request and response using
the @Consumes
and @Produces
annotations, respectively. These annotations may be specified on the
resource class or a resource method. The annotation specified on the
method overrides any on the resource class.
Here is an example showing how Order
can be published
using multiple MIME types:
@GET @Path("{oid}") @Produces({"application/xml", "application/json"}) public Order getOrder(@PathParam("oid")int id) { . . . }
The resource method can generate an XML or JSON representation of
Order
. The exact return type of the response is determined by
the HTTP Accept
header in the request.
Wildcard pattern matching is supported as well. The following
resource method will be dispatched if the HTTP Accept
header specifies any
application
MIME type such as application/xml
,
application/json
, or any other media type:
@GET @Path("{oid}") @Produces("application/*") public Order getOrder(@PathParam("oid")int id) { . . . }
Here is an example of how multiple MIME types may be consumed by a resource method:
@POST @Path("{oid}") @Consumes({"application/xml", "application/json"}) public Order getOrder(@PathParam("oid")int id) { . . . }
The resource method invoked is determined by the HTTP
Content-Type
header of the request.
A mapping between a custom representation and a corresponding Java
type can be defined by implementing the MessageBodyReader
and
MessageBodyWriter
interfaces and annotating with @Provider
.
By default, a new resource is created for each request to access the resource.
The resource method parameters, fields, or bean properties are bound using
annotations during object
creation time. In addition to xxx
Param@PathParam
and
@QueryParam
, the following annotations can be used to bind different parts of
the request to a resource method parameter, field, or bean property:
@CookieParam
binds the value of a cookie:
public Order getOrder( @CookieParam("JSESSIONID")String sessionid) { //. . . }
This code binds the value of the "JSESSIONID"
cookie to the resource method parameter sessionid
.
@HeaderParam
binds the value of an HTTP header:
public Order getOrder( @HeaderParam("Accept")String accept) { //. . . }
@FormParam
binds the value of a form parameter contained within a request
entity body. Its usage is displayed in an earlier section.
@MatrixParam
binds the name/value parameters in the URI path:
public List<Order> getAll( @MatrixParam("start")int from, @MatrixParam("page")int page) { //. . . }
And the resource is accessed as:
http://localhost:8080/store/webresources/orders; start=10; page=20
Then 10
is mapped to the from
parameter and 20
is mapped to the page
parameter.
More details about the application deployment context and the
context of individual requests can be obtained using the @Context
annotation.
Here is an updated resource definition where more details about the request context are displayed before the method is invoked:
@Path("orders") public class Orders { @Context Application app; @Context UriInfo uri; @Context HttpHeaders headers; @Context Request request; @Context SecurityContext security; @Context Providers providers; @GET @Produces("application/xml") public List<Order> getAll(@QueryParam("start")int from, @QueryParam("end")int to) { //. . .(app.getClasses()); //. . .(uri.getPath()); //. . .(headers.getRequestHeader( HttpHeaders.ACCEPT)); //. . .(headers.getCookies()); //. . .(request.getMethod()); //. . .(security.isSecure()); //. . . } }
In this code:
UriInfo
provides access to application and request URI
information.
Application
provides access to application configuration information.
HttpHeaders
provides access to HTTP header information either as a
Map
or convenience methods. Note that @HeaderParam
can also be used to bind an HTTP header to a resource method parameter, field,
or bean property.
Request
provides a helper to request processing and is typically used
with Response
to dynamically build the response.
SecurityContext
provides access to security-related information of the current
request.
Providers
supplies information about runtime lookup of provider instances
based on a set of search criteria.
An application-specific exception may be thrown from within the resource method and
propagated to the client. The application can supply checked or exception
mapping to an instance of the Response
class. Let’s say the
application throws the following exception if an order is not
found:
public class OrderNotFoundException extends RuntimeException { public OrderNotFoundException(int id) { super(id + " order not found"); } }
The method getOrder
may look like:
@Path("{id}") public Order getOrder(@PathParam("id")int id) { Order order = null; if (order == null) { throw new OrderNotFoundException(id); } //. . . return order; }
The exception mapper will look like:
@Provider public class OrderNotFoundExceptionMapper implements ExceptionMapper<OrderNotFoundException> { @Override public Response toResponse( OrderNotFoundException exception) { return Response .status(Response.Status.PRECONDITION_FAILED) .entity("Response not found") .build(); } }
This ensures that the client receives a formatted response instead of just the exception being propagated from the resource.
18.118.93.175