REST Services Cheat sheet

Here is a comprehensive JAX-RS Cheatsheet to help you code your REST Services.

JAX RS-Annotations

@Path: Path to annotate a method or a Class with the resource path it represents. For instance:

@Path("/hello")
public class CustomerEndpoint {
}

@Produces: To specify the output type that the resource produces, or in a narrower scope the type of output that a method in a resource. For example:

@Produces(MediaType.TEXT_PLAIN)
@Produces(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_JSON)

@Consumes: To specify the type of input that the resource consumes, or in a narrower scope the type of input that a method in a resource consumes. For instance:

@Consumes(MediaType.TEXT_PLAIN)
@Consumes(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_JSON)

@ApplicationPath: Identifies the application path that serves as the base URI for all resource URIs provided by path. For example:

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
 
@ApplicationPath("/rest")
public class RestActivator extends Application {
     
}

@Context: lets you inject contextual objects such as UriInfo, which provides contextual request-specific information about the request URI. For instance:

@Path("/")

public class DemoResource {

    private final @Context HttpHeaders httpHeaders;
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getHeaders(){
        // Code here that uses httpHeaders
    }
}

HTTP Operations: JAX-RS defines five annotations that map to specific HTTP operations:

  • @javax.ws.rs.GET: To map an HTTP GET Request
  • @javax.ws.rs.PUT: To map an HTTP PUT Request
  • @javax.ws.rs.POST: To map an HTTP POST Request
  • @javax.ws.rs.DELETE: To map an HTTP DELETE Request
  • @javax.ws.rs.HEAD: To map an HTTP HEAD Request

JAX RS Parameters

@QueryParam allows to inject Query Parameters in your Endpoint. For example:

public Response getParams(
    @QueryParam("param1") @DefaultValue("") String myStr,
    @QueryParam("param2") @DefaultValue("-1") int myInt) {
    String s = "param1=" + myStr + ", param2=" + myInt;
    return Response.ok(s).build();
}
$ curl 'http://localhost:8080/queryParam?param=Hi&param2=123'

@MatrixParam applies to a particular path element while query parameters apply to the request as a whole. For example:

@GET
@Path("matrixParam")
public Response getMatrixParam(
    @MatrixParam("height") int height,
    @MatrixParam("width") int width) {
  return Response.ok("height=" + height + ", width=" + width).build();
}
$ curl http://localhost:8080/matrixParam;height=1;width=2

@PathParam

@GET
@Path("pathParam/{p}")
public Response getParams(@PathParam("p") String v) {
  return Response.ok(v).build();
}
$ curl http://localhost:8080/pathParam/foo

@HeaderParam

@GET
@Path("headerParam")
public Response getHeaderParam(@HeaderParam("p") String v) {
  return Response.ok(v).build();
}
$ curl -v -H 'p: foo' http://localhost:8080/headerParam

@CookieParam

@GET
@Path("cookieParam")
public Response getCookieParam(@CookieParam("p") String v) {
  return Response.ok(v).build();
}
$ curl -v -H 'Cookie: p=foo' http://localhost:8080/cookieParam

@FormParam

@POST
@Path("formParam")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response postFormParam(@FormParam("p") String v) {
  return Response.ok(v).build();
}
$ curl -v -d 'p=foo' http://localhost:8080/formParam

@BeanParam

@POST
@Path("beanParam")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response postBeanParam(@BeanParam Image image) {
  String s = "height=" + image.getHeight();
  s += ", width=" + image.getWidth();
  return Response.ok(s).build();
}

import javax.ws.rs.FormParam;

public class Image {

  @FormParam("height")
  private int height;

  @FormParam("width")
  private int width;

  public int getHeight() {
    return height;
  }

  public int getWidth() {
    return width;
  }
}
$ curl -d 'height=1' -d 'width=2' http://localhost:8080/beanParam 

How to produce a Response

Response with status OK. For example:

String message = "This is a text response";

return Response
  .status(Response.Status.OK)
  .entity(message)
  .build();

Response in custom format. For example:

String json = //convert entity to json
return Response.ok(json, MediaType.APPLICATION_JSON).build();

Throwing Exception

@GET
@Path("{id}")
@Produces("application/xml")
public Customer getCustomer(@PathParam("id") int id) {

   Customer cust = findCustomer(id);
   if (cust == null) {
     throw new WebApplicationException(Response.Status.NOT_FOUND);
   }
   return cust;
}

JAX WS Client API

Client client = ClientBuilder.newClient();
SimpleProperty p1 = new SimpleProperty("mykey","value");
WebTarget myResource = client.target(BASE_URL+"/param/add");

Response rs = myResource.request(MediaType.APPLICATION_XML)
        .post(Entity.xml(p1), Response.class);

assertEquals(rs.getStatus(),200);
String out = rs.readEntity(String.class);
assertEquals(out,"Success");

Async API

Sample Async method:

@GET
@Path("/xmlasync/{id}")
@Produces(MediaType.APPLICATION_XML)
public void asyncGet(final @Suspended AsyncResponse asyncResp,
	final @PathParam("id") int id) {
		asyncResp.setTimeout(10, TimeUnit.SECONDS);
		asyncResp.setTimeoutHandler(new MyTimeoutHandler());
		new Thread(new Runnable() {
			public void run() {
				SimpleProperty p = ejb.getList().get(id);
				asyncResp.resume(p);
			}
	}).start();
}

public class MyTimeoutHandler implements TimeoutHandler {
	public void handleTimeout(AsyncResponse asyncResp) {
		Response r = Response.serverError().status( HttpURLConnection.
		HTTP_UNAVAILABLE).build( );
		asyncResp.resume( r );
	}
}

Filters: Used to modify Request or Response Headers

Server side filters: Decorate Request:

import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerRequestContext;

@Provider
@PreMatching
public class HttpMethodOverride implements ContainerRequestFilter {
   public void filter(ContainerRequestContext ctx) throws IOException {
      String methodOverride = ctx.getHeaderString("X-Http-Method-Override");
      if (methodOverride != null) ctx.setMethod(methodOverride);
   }
}

Server side filters: Decorate Response:

import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerRequestContext;

@Provider
@PreMatching
public class HttpMethodOverride implements ContainerRequestFilter {
   public void filter(ContainerRequestContext ctx) throws IOException {
      String methodOverride = ctx.getHeaderString("X-Http-Method-Override");
      if (methodOverride != null) ctx.setMethod(methodOverride);
   }
}

Client side filters: Decorate Request:

import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.ClientRequestContext;

public class ClientCacheRequestFilter implements ClientRequestFilter {
   private Cache cache;

   public ClientCacheRequestFilter(Cache cache) {
      this.cache = cache;
   }

   public void filter(ClientRequestContext ctx) throws IOException {
      if (!ctx.getMethod().equalsIgnoreCase("GET")) return;

      CacheEntry entry = cache.getEntry(request.getUri());
      if (entry == null) return;

      if (!entry.isExpired()) {
         ByteArrayInputStream is = new ByteArrayInputStream(entry.getContent());
         Response response = Response.ok(is)
                                     .type(entry.getContentType()).build();
         ctx.abortWith(response);
         return;
      }

      String etag = entry.getETagHeader();
      String lastModified = entry.getLastModified();

      if (etag != null) {
         ctx.getHeaders.putSingle("If-None-Match", etag);
      }

      if (lastModified != null) {
         ctx.getHeaders.putSingle("If-Modified-Since", lastModified);
      }
   }

}

Client side filters: Decorate Response:

public class CacheResponseFilter implements ClientResponseFilter {
   private Cache cache;

   public CacheResponseFilter(Cache cache) {
      this.cache = cache;
   }

   public void filter(ClientRequestContext request,
                      ClientResponseContext response)
            throws IOException {
      if (!request.getMethod().equalsIgnoreCase("GET")) return;

      if (response.getStatus() == 200) {
         cache.cacheResponse(response, request.getUri());
      } else if (response.getStatus() == 304) {
         CacheEntry entry = cache.getEntry(request.getUri());
         entry.updateCacheHeaders(response);
         response.getHeaders().clear();
         response.setStatus(200);
         response.getHeaders().putSingle("Content-Type", entry.getContentType());
         ByteArrayInputStream is = new ByteArrayInputStream(entry.getContent());
         response.setInputStream(is);
      }
   }
}

Interceptors: Reader and Writer Interceptors are used to control the Message Body

Writer Interceptor:

@Provider
public class GZIPEncoder implements WriterInterceptor {

   public void aroundWriteTo(WriterInterceptorContext ctx)
                    throws IOException, WebApplicationException {
      GZIPOutputStream os = new GZIPOutputStream(ctx.getOutputStream());
      ctx.getHeaders().putSingle("Content-Encoding", "gzip");
      ctx.setOutputStream(os);
      ctx.proceed();
      return;
   }
}

Reader Interceptor:

@Provider
public class GZIPDecoder implements ReaderInterceptor {
   public Object aroundReadFrom(ReaderInterceptorContext ctx)
                                throws IOException {
      String encoding = ctx.getHeaders().getFirst("Content-Encoding");
      if (!"gzip".equalsIgnoreCase(encoding)) {
         return ctx.proceed();
      }
      GZipInputStream is = new GZipInputStream(ctx.getInputStream());
      ctx.setInputStream(is);
      return ctx.proceed(is);
   }
}

JAX-RS Dependency for WildFly

<dependency>
      <groupId>org.jboss.spec.javax.ws.rs</groupId>
      <artifactId>jboss-jaxrs-api_2.1_spec</artifactId>
      <scope>provided</scope>
</dependency>

JAX-RS Cheatsheet by mastertheboss.com – All rights reserved

Found the article helpful? if so please follow us on Socials