JAX-RS Tutorial – Create Jakarta RESTful Web Services

Last Updated:  May 13, 2020 | Published: September 29, 2019

The REST architectural pattern is widely adopted when it comes to creating web services. The term was first introduced by Roy Fielding in his dissertation and describes a way for clients to query and manipulate the resources of a server. With Jakarta RESTful Web Services (JAX-RS), formerly known as Java API for RESTful Web Services, we have a standardized approach to create such web services. This specification is also part of the MicroProfile project since day one.

Learn more about the Jakarta RESTful Web Services (JAX-RS) specification, its annotations and how to use it in this blog post. Please note that I won't cover every aspect of this spec (as it is quite large) and rather concentrate on the most important parts.

Specification profile: Jakarta RESTful Web Services (JAX-RS)

  • Current version: 2.1
  • GitHub repository
  • Specification homepage
  • Basic use case: develop web services following the Representational State Transfer (REST) pattern

Bootstrap a JAX-RS application

Bootstrapping a JAX-RS application is simple. The main mechanism is to provide a subclass of javax.ws.rs.core.Application on your classpath:

With @ApplicationPath you can specify the path prefix all of your REST endpoints should share. This might be /api or /resources. Furthermore, you can override the methods of Application  and register for example all your resources classes, providers and features manually (getClasses() method), but you don't have to.

Create REST endpoints

Most of the time you'll use JAX-RS to expose resources of your server on a given path and for a specific HTTP method.  The specification provides an annotation to map each HTTP method (GET, PUT, POST, DELETE …) to a Java method. Using the @Path annotation you can specify which path to map and also specify path variables:

In the example above you see that the whole class is mapped to the path /books with different HTTP methods. @PathParam is used to get the value of a path variable and @QueryParam for retrieving query parameters of a URL (e.g. ?order=DESC). In addition, you can inject further classes into your JAX-RS method and get access e.g. to the HttpServlet, UriInfo and HTTP headers of the request (@HeaderParam("nameOfHeader")).

Next, JAX-RS offers annotations for content-negotiation: @Consumes and @Produces. In the example above, I'm adding these annotations on class-level, so all methods (which don't specify their own @Produces/@Consumes) inherit the rules to accept only JSON requests and produces only JSON responses.

In the case, your client sends a payload in the HTTP body (e.g. creating a new book – @POST in the example above), you can map the payload to a Java POJO. For JSON payloads, JSON-B is used in the background and for not default payload types  (e.g. binary protobuf payload to POJO) you have to register your own MessageBodyReader and MessageBodyWriter.

The specification defines a standard set of entity providers, which are supported out-of-the-box (e.g. String for text/plain, byte[] for */*, File for */*, MultivaluedMap<String, String> for application/x-www-form-urlencoded , etc.).

Alongside synchronous and blocking REST endpoints, the specification also supports asynchronous ones:

If you don't specify any other lifecycle (e.g. with @Singleton from EJB or a CDI scope) the JAX-RS runtime instantiates a new instance for each request for this resource.

Access external resources

The JAX-RS specification also provides a convenient way to access external resources (e.g. REST endpoints of other services) as a client. We can construct such a client with the ClientBuilder from JAX-RS:

This ClientBuilder allows you to specify metadata like the connect and read timeouts, but also register several features (like you'll see in the next chapter). Make sure to not construct a new Client for every request, as they are heavy-weight objects:

Clients are heavy-weight objects that manage the client-side communication infrastructure. Initialization as well as disposal of a {@code Client} instance may be a rather expensive operation. It is therefore advised to construct only a small number of {@code Client} instances in the application. Client instances must be {@link #close() properly closed} before being disposed to avoid leaking resources.

Javadoc of the Client class

Once you have an instance of a Client, you can now specify the external resources and create a WebTarget instance for each target you want to access:

With this WebTarget instance you can now perform any HTTP operation, set additional header/cookies, set the request body and specify the response type:

Getting started with Eclipse MicroProfile Course Bundle

NEWS: Up-to-date with MicroProfile 3.3

All you need to know about MicroProfile

Looking for a resource to learn more about MicroProfile and all its specifications in-depth? Signup for the MicroProfile Course Bundle (E-Book & Video Course)

Furthermore, JAX-RS offer reactive support for requesting external resources with .rx():

Intercept the request and response flow

There are various entry points to intercept the flow of a JAX-RS resource and including client requests. To give you an idea of how the overall architecture looks like, have a look at the following image:

jaxRsRequestResponseFlow

As you see in the image above, there are several ways to apply cross-cutting logic to your JAX-RS resource method or client. I'll not cover all of the filters/readers/interceptors in this blog post, as you'll find a perfect documentation in the Jersey user guide. I'll just have a look at the most common ones.

To register your implementations, you either do it manually with your JAX-RS configuration class (see the first chapter), the .register() method of the ClientBuilder, or use @Provider to register it globally.

First, you can apply a filter that executes before JAX-RS maps an incoming request to your resource method. For this, you need the @PreMatching annotation and can do evil things like the following:

Next, you can add e.g. common headers to the response of your resource method with a ContainerResponseFilter:

With @Priority you can set the order of your filter once you use multiple and rely on execution in order.

For the client-side, we can add a filter to first log all HTTP headers of the incoming response with @ClientResponseFilter:

YouTube video for using JAX-RS 2.1

Watch the following YouTube video of my Getting started with Eclipse MicroProfile series to see JAX-RS 2.1 in action:

You can find the source code with further instructions to run this example on GitHub.

Have fun using JAX-RS,

Phil

 

  • Hi bro, Im quite enjoying articles on your blog. They are structured properly, easy to digest and memorize, despite English being my second language. Wish you well.

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

    Sign up for Our Mailing List And Get

    the Testing Java Applications ($9) Cheat Sheet for Free

    Testing Java Applications Cheat Sheet Cover
    >