DEV Community

Andy McCright
Andy McCright

Posted on • Originally published at andymc12.net on

Book Excerpt: Real World Jakarta REST Example

The following in an excerpt from Practical Cloud-Native Java Development with MicroProfile from Packt Publishing. It is available for pre-order from Amazon.com and directly from Packt. It is scheduled for release in September. This excerpt comes from chapter 4: Building Cloud-Native Applications and describes how to build a more real-world RESTful application using Jakarta REST (aka JAX-RS):


A More Real-world Example

Now that we have built a simple JAX-RS application, let’s build a more complex application – a thesaurus service where clients can search and update synonymous words. First, we’ll start with an exception mapper:

@Provider
public class NoSuchWordExceptionMapper implements ExceptionMapper<NoSuchWordException> {

    @Override
    public Response toResponse(NoSuchWordException ex) {
        return Response.status(404)
                       .entity(ex.getMessage())
                       .build();
    }
}

Enter fullscreen mode Exit fullscreen mode

Most applications will have business exceptions – exceptions specific to the application domain. For a thesaurus service, that might include a NoSuchWordException, which could be used to indicate that a searched word does not exist. It is clear in the application that somebody specified a word that does not exist, but it is not clear to an HTTP client. The provider class, NoSuchWordExceptionMapper, makes that possible. It enables the resource class methods to throw a NoSuchWordException, and the JAX-RS container will map the exception to an HTTP response (in this case, a 404 Not Found).

Next is the resource class (full source code available at: https://github.com/PacktPublishing/Practical-Cloud-Native-Development-with-MicroProfile-4.0/blob/main/Chapter04/src/main/java/com/packt/microprofile/book/ch4/thesaurus/ThesaurusResource.java):

@Path(“/thesaurus/{word}”)
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.TEXT_PLAIN)
public class ThesaurusResource { // … 

Enter fullscreen mode Exit fullscreen mode

There are a few new annotations on the resource class: @Produces and @Consumes. These annotations can be placed on resource classes or methods – like most annotations of this type in JAX-RS, annotations on the method take priority over annotations on the class. These annotations help control the matching of requests and the entity providers (MessageBodyReaders and MessageBodyWriters) to be used in deserializing the HTTP entity from the request or serializing the HTTP entity in the response.

HTTP requests and responses may contain a header that indicates the media type (also known as MIME type) of the HTTP entity – Content-Type. HTTP requests may also contain a header that specifies the media type(s) that it expects to receive in the response – Accept. In the absence of these headers, all media types are allowed (i.e., */*).

In the previous example, the resource class specifies MediaType.TEXT_PLAIN, or text/plain. Other media types include text/html, application/json, application/xml, image/jpeg, and much more. By specifying text/plain, that would prevent the resource methods from being invoked if a request contained a header like Content-Type: application/pdf or Accept: image/png – instead of invoking the resource method, the JAX-RS container would return a 415 Unsupported Media Type error.

Best practice:
Always use @Produces and @Consumes to limit media types. This will place limits on the types of requests your service will respond to. It will ensure that your application (if properly tested) can handle requests of the specified media types.

This example also introduces new method-level HTTP verb annotations: @POST, @PUT, @DELETE and @PATCH. Like @GET, these annotations specify which method should be invoked based on the HTTP request’s verb (also known as method – HTTP method is probably the more commonly used term, but we will use verb in this book to disambiguate from Java methods). The JAX-RS API set includes these five verb annotations as well as @HEAD and @OPTIONS that are less commonly used.

Special note:
If the resource class contains a method annotated with @GET but not @HEAD, the JAX-RS container would invoke the @GET method for matching HTTP HEAD requests, but it would remove the entity. Likewise, if a resource class contains any HTTP verb annotation other than @OPTIONS, the JAX-RS container would return a response indicating all of the valid verbs that could be matched for that request. Using the example above, an OPTIONS request would result in a response with a header like, Allow: DELETE, HEAD, GET, OPTIONS, PATCH, POST, PUT.

This example also introduces the idea of HTTP parameters, specifically:

@PathParam(“word”) String word;

This annotation can be placed on fields or method parameters. The value of @PathParam is word which corresponds to the template variable in the resource class’s @Path value (“/thesaurus/{word}”). This means that for an HTTP request like http://localhost:9080/myApp/rest/thesaurus/funny, the value injected in to the word field would be funny.

There are other HTTP parameter types that can be used in JAX-RS including @QueryParam, @FormParam, @CookieParam, @HeaderParam, @MatrixParam which all correspond to different parts of an HTTP request. JAX-RS also allows multiple HTTP parameter annotations to be aggregated on a single Java class and then referenced in the resource class or method as a @BeanParam.


I hope you found this excerpt helpful and enticing. Chapter 4 is packed (pun intended) full of useful knowledge for building and consuming robust RESTful services. It covers the basics, but also a lot of hidden gems in JAX-RS, JSON-B/P, CDI and MicroProfile Rest Client. And if that’s not enough, there’s eleven more chapters filled with cloud-native goodness. Ok, that’s enough advertising for one blog post… 🙂 Thanks for reading!

Top comments (0)