Anda di halaman 1dari 19

HTTP Method and URI Matching:

@Path
|-Binding URIs
|-@Path Expressions
|-Template Parameters
|-Problems with Query Params
|-Benefits of @Path Expressions
|-Differences between the Query and Template Params
|-Regular Expressions
|-Matrix Parameters
|-Differences between the Query, Path and Matrix Params and when to use them
Sub Resource Locators
|-Full Dynamic Dispatching
Terminology in REST Resource
@Path:
@Path can have complex matching expressions so that you can be more specific on
what requests get bound to which incoming URIs. @Path can also be used on a Java
method as sort of an object factory for sub-resources of your application.

@Path("/order")
class OrderResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String track(@QueryParam("orderID") String orderID) {
return "status for orderID : " + orderID + " is : processed";
}

@GET
@Produces(MediaType.TEXT_PLAIN)
public String getOrderDetails(@QueryParam("orderID") String orderID) {
return "ordered Date : " + new Date() + " no of products 2";
}
}
In the above code there is an ambiguity in modelling the resources bcz with one single
URI 2-methods has been matched JAX-RS will leads into an ambiguity. So in order to
avoid this ambiguity we need to go for Binding URI's.
Binding URI's:
The @javax.ws.rs.Path annotation in JAX-RS is used to define a URI matching pattern
for incoming HTTP requests. It can be placed upon a class or on one or more Java
methods as well to avoid the ambiguious URI's.

For a Java class to be eligible to receive any HTTP requests, the class must be
annotated with at least the @Path("/") expression. These types of classes are called
JAX-RS root resources.

To receive a request, a Java method must have at least an HTTP method annotation
like @javax.ws.rs.GET applied to it. This method is not required to have an @Path
annotation on it but if we want we can write/bind @Path at method level with one
more URI called as Binding URI.

@Path("/order")
class OrderResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getOrderDetails(@QueryParam("orderID") String orderID) {
return "ordered Date : " + new Date() + " no of products 2";
}

@Path("/track")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String track(@QueryParam("orderID") String orderID) {
return "status for orderID : " + orderID + " is : processed";
}
}

Here req by default maps to the getOrderDetails() method and if we send req with
additional URI then req's binds to the track().

Access the application


http://localhost:8080/10.1BindingURIs/resources/order?orderID=121
Ordered Date : Thu Mar 24 08:19:23 IST 2016 no of products 2

http://localhost:8080/10.1BindingURIs/resources/order/track?orderID=121
Status for orderID : 121 is : processed
@Path Expressions:
@Path("/customers")
public class CustomerResource {
@GET
@Path("/details")
public String getCustomer(@QueryParam("id") int id) {
...
}
}
Access the Resource
http://localhost:8080/CustomerWeb/resources/customers/details?id=133

Problems with Query Params:


1. We need to know and remember the Query params to access the reource
2. Syntax of supplying the query params need to know to supply the req data like by
appending "?" and then appending "&" if we have multiple Query params.
Here in order to access the Resource we need to know the Query param names and if
we have more no.of Query Params then it is harder to remember the Query Param
names so in order avoid the complexity in accessing the Resource we will go for @Path
Expressions.
The value of the @Path annotation is usually a simple string, but you can also define
more complex expressions to satisfy your URI matching needs.
There are 2-types Expressions are there
1. Template parameters
2. Regular Expressions
1. Template parameters:
We wrote a customer access service that allowed us to query for a specific customer
using a wildcard URI pattern.

@Path("/customers")
public class CustomerResource {
@GET
@Path("/details/{id}")
public String getCustomer(@PathParam("id") int id) {
...
}
}

http://localhost:8080/CustomerWeb/resources/customers/details/333
The {id} expression represents a template parameter which is reserved position or
place holder as part of the req URI path hence these are also called as Path Params.
A template parameter is a named wildcard pattern embedded within the value of an
@Path annotation. It starts with an open brace, "{", continues with one or more
alphanumeric characters, and ends with a closed brace "}". The expression represents
one or more characters that are not the slash "/" character.
So now the client will sends the data as part of path of the URI without referring the
param names. For example of a GET will be matched as /customers/details/333
request would match getCustomer(), but a GET request /customers/details/333/444
would not match the path expression.
These template parameters can be embedded anywhere within an @Path declaration.

@Path("/customers")
public class CustomerResource {
@GET
@Path("details/{id}-{custname}")
public String getCustomer(@PathParam("id") int id,
@PathParam("custname") String custname) {
...
}
}
In our example, the URI is constructed with a customer’s id name, followed by a
hyphen, ending with the custname of the individual. So, the GET request
/customers/details/333 would no longer match to getCustomer(), but a GET req
/customers/details/333-dbreddy request would.

@Path("/customers/{id}")
public class CustomerResource {
@GET
@Path("/details/{custname}")
public String getCustomer(@PathParam("id") String id,
@PathParam("custname") String custname) {
...
}
}
Access the application (In ARC or Browser but it will not accessible in Eclipse browser):
http://localhost:8080/10.2.1TemplateParams/resources/
customers/333/details/dbreddy
Response:
Customer Details:
Name: dbreddy
Cust-id: 333

Benefits of @Path Expressions:


Easy to remember
Easy to understand and we don't need to remember the additional param names to
access the resource and easy to readable
Differences between the Query and Template Params:
1. Path params is mandatory but Query params are optional. That means if any param
value we didn't pass it resolved to null of default values in case of Query params but
not null in the Template params. As Query params can taken as null in the absence
of multiple param values hence it can be accessible but Template cannot be null hence
we cannot access the Resource.
Example:
With an Query Param we can access the Resource as /customers/details?id=333 (bcz
Query params are optional)
With an Path Param we cannot access Resource using /customers/details/333 rather
we need to access only by using /customers/details/333-dbreddy (Bcz Template
params are mandatory)
2. Path params will influences the way the req will be resolved and can appear in
anywhere in the URI but req cannot be resolved based on the Query params. That
means Query Params and Template Params will appeared as part of the URI, but the
difference is that the template parameters can be embedded/appeared anywhere
within URI with reserved locations of the URI path but query params always can be
appeared at the end of the URI only. So req can be resolved based on the Path params
but not using the Query Params.
@Path("/customers/{id}")
public class CustomerResource {
@GET
@Path("/details/{custname}")
public String getCustomer(@PathParam("id") String id,
@PathParam("custname") String custname) {
...
}
}

With an Query Param we can access the Resource as


/customers/details?id=C333&custname=dbreddy (that means the req cannot be
resolved based on the query params rather it will resolved based on the URI only)
With an Path Param we cannot access Resource using
/customers/details/C333/dbreddy that means the way in which req will be different
from the Query params in case of Template params
With an Path Param we can access Resource using /customers/333/details/dbreddy
In case of Path params the req can be accessed based on the URI and as well as Path
params reserved position hence req Path params will have role on resolving the req
along with URI of the req bcz Path params are mandatory.
3. Multi values cannot be passed for an single valued param in case of Template
params but in case of Query params we can pass multiple vales for single param bcz
it will ignores additional etc values.
Example:
@Path("/bank")
class BankResource {
public float getBalance(@QueryParamString acNo) {
....
}
}

With Query params /bank?accNo=AC12323&accNo=AC2323 (bcz it ignores additional


req data)
With Path params /bank?accNo=AC12323&accNo=AC2323 cannot be possible (bcz it
cannot ignores additional req data)
Use case:
We can give the location so that Google maps will gives Location Zip code.
@Path("/postal/{area}")
public class PostalResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public int locateZip(@PathParam("area") String area) {
return 500073;
}
}

What is Template Params when to use Template Params?


When the parameters is mandatory in accessing the req and params want to be passed
in anywhere of the URI then we need to use Template params otherwise go for the
Query params.
Regular Expressions:
@Path expressions are not limited to simple wildcard matching expressions. For
example, our resource method wants to take only integer parameter that means a
kind of validation has to be impose on the params that we wanted to give as param
values that's where we need to use Regular Expressions.
Purpose:
A regular expression is an object that describes a pattern of characters.
Regular expressions are used to perform pattern-matching and "search-and-replace"
functions on text nd it can be used as validation of the pattern data or param data.

@Path("/airtelmobile")
public class AirtelMobileServiceActivatorResource {

/*
* Here \\d+ any no.of digits and and d{10} means only digits and that
* should be 10-digits only Here .* means any characters
*/

/*
* Here \\d{10} meant for to accept 10-digit mobileNo and .* meant for
* either prepaid or postpaid any thing as string
*/
/*
* Expression [789]{1}\\d{9} meaning is start with 7/8/9 which can occur
* only once and \\d{9} indicates 9-digits from range 0-9. so finally we
* will get 1+9=10 digit number
*/
@Path("/status/{mobileNo : [789]{1}\\d{9}}/{type : .*}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getMobileNoStatus(@PathParam("mobileNo") long mobileNo,
@PathParam("type") String type) {
return "Status: Your " + type + " MobliNo : " + mobileNo
+ " will be activated in 24-hours";
}
}

We have taken our {mobileNo} expression and changed it to {id : [789]{1}\\d{9}}.


The mobileNo as digits is the identifier of the expression. If we want we can reference
it with using @PathParam as well and it is delimited by ":" character.
Regular expressions are part of a string matching language that allows you to express
complex string matching patterns. In this case, \\d+ matches one or more digits. Here
\\d means digit and + means one or more digits.
Case: 1
Access the application without writing the regular expression for mobileNo as
http://localhost:8080/10.3RegularExpression/resource/airtelmobile
/status/M299D99999/prepaid
We will get NumberFormatException in the Server console.
Case: 2
If we model using Regular expressions for mobileNo then it validates and matches the
req which is taking string as mobileNo but no resource will found bcz our resource is
mobileNo is long type so string will not matches with long hence it will not throws
NumberFormatException rather it sends 404 stating that resource not found so that
we can display a proper message to the client it is bcz of Reg Expression only and
example response is shown below.
http://localhost:8080/10.3RegularExpression/resource/airtelmobile/status/M299D99
999/prepaid
404: Not Found (means resource is not available)
Case: 3
If we send exact validation number then we will get below response
http://localhost:8080/10.3RegularExpression/resource/airtelmobile/status/9999999
999/prepaid
Status: Your prepaid MobliNo : 9999999999 will be activated in 24-hours

Regular expressions are not limited in matching one segment of a URI it can be for
multiple segments as well.
Similarly we can implement any type of Regular Expressions as part of the RESTful
services as well bcz it has a support for Regular Expressions.
Advantages of Regular Expression in RESTful:
In RESTful services if we use Regular Expressions then these will make our resource
can be accessible if and only if proper data is matched otherwise it makes resource
not found so that we can avoid throwing Exceptions. That means it stops accessing
the resource if data format is not proper so that we can avoid accessing the resource
with wrong data.
Matrix Parameters:
Matrix parameters are name-value pairs embedded within the path of a URI string.
It is not a concept of java rather it is concept of Http protocol which is has been added
as part of Http 1.1
JAX-RS 1.1 doesn't had a support for Matric params but it has been added in JAX-RS
2.0
For example:
http://example.cars.com/mercedes/e55;color=black/2006
They come after a URI segment and are delimited by the “;” character. The matrix
parameter in this example comes after the URI segment e55. Its name is color and
its value is black. Matrix parameters are different than query parameters, as they
represent attributes of certain segments of the URI and are used for identification
purposes.
Query parameters, on the other hand, always come at the end of the URI and always
pertain to the full resource you are referencing.
Matrix parameters are ignored when matching incoming requests to JAX-RS resource
methods. It is actually illegal to specify matrix parameters within an @Path
expression.

For example:
@Path("/car-agent")
class CarAgent {
@Path("/search/{make}/{model}")
@GET
@Produces("text/plain")
public String search(@PathParam("make") String make,
@MatrixParam("year") int makeYear,
@PathParam("model") String model,
@MatrixParam("capacity") int seatCapacity,
@QueryParam("color") String color,
@QueryParam("price") float price) {

// Query and Matrix param are optional


....
}
}

If we wanted to search car we can use Path params but if we search a Marathi of
vegnor or swift then we need that model year as 2006 model which is an additional
data then we can use Matrix params for this use case.
If we search for Marathi with swift then we wanted to search for capacity as 4 then
we can use Matrix params.
These can be attached to a specific part/segment of path as part of URI Like this we
send any no.of Matrix params as well.
Access the application:
http://localhost:8082/10.4MatrixParams/resources/car-
agent/search/maruthi;year=2006/swift;capacity=4?color=red&price=12000

Response:
Make : maruthi
Model : swift
SeatCapacity: 4
Color : red
Price : 12000.0
We can send all matrix params as well and we can some of them as well ncz Matrix
params are optional.

http://localhost:8082/10.4MatrixParams/resources/car-
agent/search/maruthi/swift?color=red
Response:
Make : maruthi
Model : swift
SeatCapacity: 0
Color : red
Price : 0.0

We should not send Matrix params after the Query params bcz Query Params always
to be last. If we send Matrix params after the Query params we will get un-expected
response and sometimes we cannot access the resource. Hence we need to send
Matrix params before the Query param and anywhere of part/segment of path of URI
that means order doesn't matters.
Example:
http://localhost:8082/10.4MatrixParams/resources/car-agent/search/maruthi/swift?
color=red;capacity=4&price=120000
Response:
Make : maruthi
Model : swift
SeatCapacity: 0
Color : red;capacity=4
Price : 120000.0

Actually we need to get SeatCapacity: 4 but it has shown as SeatCapacity: 0 and we


didn’t return capacity=4 but it came as response which is un-expected response.
Example:
http://localhost:8080/10.4MatrixParams/resources/car-
agent/search/maruthi;capacity=4/citi;year=2006?color=red&price=12000
Response:
Entered Model is: citi
Make : maruthi
SeatCapacity: 0
Year: 2006
Color : red
Price : 12000.0

http://localhost:8080/10.4MatrixParams/resources/car-
agent/search/honda;year=2006/citi;capacity=4?color=red&price=12000
(Observe the order of Matrix params in URI)
Response:
Entered Model is: citi
Make : honda
SeatCapacity: 4
Year: 0
Color : red
Price : 12000.0

If we observe above 2-responses even though we are passing 2-matrix params we


can access only one them bcz scope of the Matrix param is at part of the path level
only but on entire URI scope. If we wanted to access all the Matrix params we need
to send all the params in a single part/segment of the path which is shown below.

http://localhost:8080/10.4MatrixParams/resources/car-agent/search/maruthi/
citi;capacity=4;year=2006?color=red&price=12000
Response:
Entered Model is: citi
Make : maruthi
SeatCapacity: 4
Year: 2006
Color : red
Price : 12000.0

http://localhost:8080/10.4MatrixParams/resources/car-agent/
search/marutki/vegnor;capacity=4;year=2006?color=red&price=12000
Response:
make : maruthi
Model : vegnor
Year: 2006
Color : red
Price : 12000.0

http://localhost:8080/10.4MatrixParams/resources/car-
agent/search/marutki/swift;capacity=4;year=2006?color=red&price=12000
Response:
Make : marutki
Model : swift
SeatCapacity: 4
Color : red
Price : 12000.0

How many we can send the data as part of path of the URI?
We can send in 3-ways by using Query, Path and Matrix Params
Differences between the Query, Path and Matrix Params and when to use
them:
Irrespective of parans we can send the data as part of path of the URI.
1. Query and Matrix params are optional but Template params are mandatory.
2. Query params always can appear at end of the req URI. Template params can be
appear in anywhere of the URI and these params are mandatory. Matrix params can
be appear in where in the req of part of path of URI and before the Query params.
3. The Template params involves/influences the way of resolving the req bcz these
are mandatory but not by Query or Matrix params bcz they are optional.
4. The scope of the Matrix params is part/segment scope but not entire URI but the
Template params scope is of entire req URI level. The scope of Query param is also
entire req scope but scope is not make sense for Query params bcz these are always
can be appear at end of the req URI but scope make sense for Matrix and Template
bcz these can be passed in anywhere of the req.
5. We can send multi-values for an single param in case of Query and Matrix (in case
of multiple values it takes 1st values only) but we cannot send in case of Template
param.
Example:
http://localhost:8080/10.4MatrixParams/resources/car-agent/ search/maruthi
/citi;capacity=4;year=2009;year=2006?color=red&price=12000&price=9000
Response:
Entered Model is: citi
Make : maruthi
SeatCapacity: 4
Year: 2009
Color : red
Price : 12000.0

Note:
We cannot access multiple values for single param by using Matrix params.
Sub Resource Locators:
The JAX-RS has capability to statically bind URI patterns expressed through the @Path
annotation to a specific Java method. JAX-RS also allows us to dynamically dispatch
requests our-self through sub resource locators. Sub resource locators are Java
methods annotated with @Path, but with no HTTP method annotation, like @GET,
applied to them. This type of method can returns an object type or specific object
type, a JAX-RS annotated service that knows how to dispatch the remainder of the
request.
Let’s consider by expanding our courier business as JAX-RS service. Let’s say our
courier can be work in different ways based on the geographic regions like
domestic/national or international. We want to add this information to our URI
scheme.

@Path("/courier")
class CourierResource {
@Path("/domestic/{docID}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getCourierStatus(@PathParam("docID") int docID) {
//docID means domestic courier ID
return "doc ID : " + docID + " status : in-transit";
}

@Path("/international/{awbNo}")
// awbNo means air way bill no
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getCourierStatus(@PathParam("awbNo") String awbNo) {
return "awbNo : " + awbNo + " status : unknown";
}
}
There is no problem with the code but it is difficult to maintain all the meta-data in an
single Resource class if we have more no.of Resource methods. Hence in order to
prevent cluttering code in single large Resource class we will go for Sub Resource
Locators.

@Path("/courier")
class CourierResource {

//Sub resource or Sub Resource Locate methods which will locates corresponding
resource methods.
@Path("/domestic")
public DomesticCourierSubResource locateDomesticServices() {
return new DomesticCourierSubResource();
}

@Path("/international")
public InternationalCourierSubResource locateInternationalServices() {
return new InternationalCourierSubResource();
}
}

@Singleton
class DomesticCourierSubResource {

public DomesticCourierSubResource() {
System.out.println("domestic()");
}

//Resource method
@Path("/{awbNo}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getCourierStatus(@PathParam("awbNo") String awbNo) {
return "awbNo : " + awbNo + " status : in progress";
}
}

@Singleton
class InternationalCourierSubResource {

public InternationalCourierSubResource() {
System.out.println("international()");
}

//Resource method
@Path("/{docID}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getCourierStatus(@PathParam("docID") int docID) {
return "doc ID : " + docID + " status : in-transit/in progress";
}
}

The CourierResource class is our root resource. It does not service any HTTP requests
directly. The root resource class CourierResource contains the sub-resource locator
method getCourierStatus() that returns a new resource class. If the path of the
request URL is "/courier/domestic" or "/courier/international" then first of all the root
resource will be matched, then the sub-resource locator will be matched and invoked,
which returns an instance of DomesticCourierSubResource or
InternationalCourierSubResource resource class obj. Sub-resource locators enable
reuse of resource classes. A method can be annotated with the @Path annotation with
empty path (@Path ("/") or @Path("/anything") that means "/domestic" etc) which
means that the sub resource locator is matched for the path of the enclosing resource.
The JAX-RS provider uses this DmesticCourierSubResource/
InternationalCourierSubResource instance to service the remainder of the request and
then takes that obj and calls the method on that class obj with which Http methods
the req has came.

Access the application:


http://localhost:8080/11SubresourceLocators/resource/courier/domestic/DM112
DomesticCourier: awbNo : DM112 status : in progress

http://localhost:8080/11SubresourceLocators/resource/courier/international/IN112
InternationalCourier: doc ID : IN112 status : in-transit

Dynamic Dispatching:
While our previous example does illustrate the concept of sub resource locators, it
does not show their full dynamic nature.
The CourierResource locator methods are retiring user class obj type but it can return
any instance of any class. At runtime, the JAX-RS provider will introspect this
instance’s class for resource methods that can handle the request.
The CourierResource classes returned by sub-resource locators is performed at
runtime thus it is possible to support polymorphism. A sub-resource locator may
return different sub-types depending on the request (for example a sub-resource
locator could return different sub-types dependent on the role /business need).

Instead of writing 2-locator methods for 2-user class obj our CourierResource class
method can have only one locator method which will return any java.lang.Object.
JAX-RS will introspect the instance returned to figure out how to dispatch the request.
For this example, if our courier is domestic, we will use our
DomesticCourierSubResource class to service the request. If our courier is
international, we will create and retun the InternationalCourierSubResource class obj

@Path("/courier")
public class CourierResource {

@Path("/{type}")
public Object locateServices(@PathParam("type") String type) {
if (type.equals("domestic")) {
return new DomesticCourierSubResource();
} else if (type.equals("international")) {
return new InternationalCourierSubResource();
}
return null;
}
}

If send req with /courier/domestic URI pattern then CourierResource lookup requests
routed to domestic would match so it creates DomesticCourierSubResource obj and
returns similarly we can have any Couriers but always return Object type only so that
we can avoid multiple locatotr methods and req will forwaded to corresponding
Resource dynamically based on the {type}.
Access the Resource:
http://localhost:8080/11.2DynamicDispatchingSubresourceLocators/resource/courie
r/domestic/DM112
DomesticCourier: awbNo : DM112 status : in progress

http://localhost:8080/11.2DynamicDispatchingSubresourceLocators/resource
/courier/international/IN112
InternationalCourier: doc ID : IN112 status : in-transit
Terminology:
Resource class:
A Java class that uses JAX-RS annotations to implement a corresponding Web
resource.
Root resource class:
A resource class annotated with @Path. Root resource classes provide the roots of the
resource class tree and provide access to sub-resources.
Request method designator:
A runtime annotation annotated with @HttpMethod. Used to identify the HTTP request
method to be handled by a resource method.
Resource method:
A method of a resource class annotated with a request method designator (@GET etc)
that is used to handle requests on the corresponding resource.
@Path(“/courier/{id}”)
class CourierResource {
// Resource method
@GET
public String getDetails(@PathParam(“id”) String id) {
}
}
Sub Resources:
Methods of a resource class that are annotated with @Path or either sub-resource
methods or sub-resource locators. Sub-resource methods handle a HTTP request
directly whilst (whilst means whereas) sub-resource locators return an object that will
handle a HTTP request.
Sub-resource method:
A method of a resource class that is used to handle requests on a sub-resource of the
corresponding resource. That means the method which is annotated with Request
method designator (@GET etc) and @Path is called as Sub-resource method.
@Path(“/courier/{id}”)
class CourierResource {
// Sub-Resource method
@GET
@Path(“/details”)
public String getDetails(@PathParam(“id”) String id) {
}
}
Sub-resource locator:
A method of a resource class that is used to locate sub-resources of the corresponding
resource.

Anda mungkin juga menyukai