You are on page 1of 4

REST API - JX-RS

1. URL with methods make REST URI


2. Idempotence methods are the methods which will not have any side effect even when they are
called multiple times. Like GET, POST, DELETE
3. Collection URI should have contact(s) instead of just contact.
4. Header confirms what type of data needs to be sent and accepted by server and client
5. Code provide information about request processing success or failure
6. HATEOAS - Hypermedia As The Engine Of Application State. This means REST APi should return
other linked entity's URI, so that user/developer can use it to get data of linked entity.
7. Richardson Maturity model - Is your REST API fully RESTFUL
a. Level 0 - Only ONE URI to get data. I.e. All actions and data goes in message body and
not in URI
b. Level 1 - Different URI for different resources like Contact has different URI and Policy
has different.
c. Level 2 - Uses right HTTP methods and send proper codes
d. Level 3 - Sends HATEOAS information with the response like links to different resources.

Way to setup REST API


Way 1:
1. in web.xml, we need to setup to jersey servlet to handle request.
2. We need to provide which folder jersey should scan for @path annotation. This needs to
provided as init-param for jersey servlet added in first setup with param-name as
a. <param-name>jersey.config.server.provider/packages</param-name>
3. In servlet mapping define url-pattern param
a. <url-pattern>/webapi/*</url-pattern>

Way 2:
1. Create new class which extends javax.ws.rs.core.Application;. This tells application
that it’s a jersey application.
2. It would scan all the packages as we have not specified any specific package
3. Url map to is defined by using following annotation in class created in step 1
a. @ApplicationPath("webapi")

Important Points:
1. Mark the class with @Path and provide path for your API
2. Application has method getClasses which can be extended to control which resources should be
considered.
3. Resources annotated with @Path, can also be marked as @Singleton. These resources will only
be initialized once for all requests.

@Path("/messages")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
Way to access parameters from client side
Query Params
Can you be used at method params or instance params.
@QueryParam("year") int year,
@QueryParam("start") int start,
@QueryParam("size") int size,

Headers and Cookies


@HeaderParam("customerHeader") String customerHeader,
@CookieParam("clientCookie") String cookieName,

These parameters can be directly converted to specific primitive types as jersey knows its converter.
However if you want to convert it to some customer class you have defined, we need to define custom
classes
1. ParamConverterProvider
2. ParamConverter

URIInfo and Context (includes cookies and headers)


@Context UriInfo uriInfo,
@Context HttpHeaders headers,

Way to include all in one custom entity class


@BeanParam MessageFilterBean filterBean

Way to customize Response


URI uri = uriInfo.getAbsolutePathBuilder().path(newId).build();
return Response.created(uri)
/*.status(Status.CREATED)*/
.entity(newMessage).build();

Similar to ParamConvertProvider, there is a way for mapping the incoming message body or outgoing
response body to a specific custom class of your own. This can be done by implementing
1. MessageBodyWriter
2. MessageBodyReader

Exception Mapper for providing custom response


@Provider -- tells jursay that it’s a exception handler
public class DataNotFoundExceptionMapper implements
ExceptionMapper<DataNotFoundException>{

@Override
public Response toResponse(DataNotFoundException exception) {
ErrorMessage errorMsg = new ErrorMessage(exception.getMessage(),
404, "www.maitrey.com");

return Response.status(Status.NOT_FOUND)
.entity(errorMsg).build();
}}
Creating HATEOAS links for the related entities
// This is way, we can create path for sub resources.
// Template can accept the runtine values defined in your path
return uriInfo.getBaseUriBuilder()
.path(MessageResource.class)
.path(MessageResource.class, "getCommentResource" )
.resolveTemplate("messageId", message.getId())
.build()
.toString();

Content Negotiation
This is the concept where client can ask for specific content type for data returned from server. Server
can send the specific response based on content type required by client. If server does not support that
type of content, it would return error and if it does, it would send back data in requested content type.

Client can request content type by sending following header

Accept - text/xml

Based on content type requested, we can write two different methods (offcource it works for same
method as well.) to have different @produce and then return that type of data.
@Produces(value = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})

This would come handy when we want to use different methods for different type of data. Like
following
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Message> getMessages()(

And following would return xml data for same method i.e. GET
@GET
@Produces(MediaType.APPLICATION_XML)
public List<Message> getMessagesXML()(

Same concept is applied to Consumes as well, where user can use different @Consumes for different
content type for data coming in.

Content-Type - application/json
Sending and handling REST request from Client side
Client client = ClientBuilder.newClient();

WebTarget baseTarget = client.target("http://localhost:8080/advanced-


jaxrs-06/webapi/");
WebTarget messagesTarget = baseTarget.path("messages");
WebTarget singleMessageTarget = messagesTarget.path("{messageId}");

Message message1 = singleMessageTarget


.resolveTemplate("messageId", "1")
.request(MediaType.APPLICATION_JSON)
.get(Message.class);

Message newMessage = new Message(4, "My New message from JAX-RS


client", "koushik");
Response postResponse = messagesTarget
.request()
.post(Entity.json(newMessage));
if (postResponse.getStatus() != 201) {
System.out.println("Error");
}
Message createdMessage = postResponse.readEntity(Message.class);

You might also like