Jakarta REST is the solution for development of building Representational State Transfer web services on the Jakarta EE Platform. The specification is easy to learn, and it enables one to construct powerful REST APIs and it also includes APIs for working with web services as a client. As such, this specification is key to the development of microservices and cloud based applications, and it is part of the Jakarta EE Web Profile as well as the full platform.
Using the API, a web service can be developed by placing just a few annotations on a plain old Java object (POJO). The API includes annotations for performing many tasks, such as producing REST responses in specified format(s), consuming data, and performing standard data operations such as CREATE, READ, UPDATE, and DELETE. The specification also includes advanced features for development of robust REST APIs.
If using the Jakarta EE Web Profile or the full Jakarta EE Platform, Jakarta REST will be bundled so there are no additional dependencies. However, if not using either of these options, you will need to include the following dependency:
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>3.1.0</version>
</dependency>
To configure an application for Jakarta REST, a class must be created which
extends jakarta.ws.rs.core.Application
. This class must be annotated with
@ApplicationPath
, supplying the String-based root path of the URI to the
RESTful resources for the application. For instance, if an application name is
“HelloWorld” and @ApplicationPath("resources")
is specified, then the URI
format to reach any web services that are registered within the HelloWorld
application is http://hostname:port/HelloWorld/resources/«service-path»,
substituting «service-path» with the service to access. The Application
class can also be utilized to enable all REST services within the application,
or to specify individual web service classes.
To create a basic web service resource class, only the @Path
and @GET
annotations are required. The @Path
annotation can be placed on any Java class
that will be a REST resource class, and it is used to specify the URI path that
should be used to access the endpoint. The @GET
annotation should be applied
to a method to indicate that it must be called upon with an HTTP Get
call. In
the following example, assuming the use of the application name and path as
specified previously, the URI to access the ping()
method would be as follows:
http://localhost:port/HelloWorld/resources/jakartaee10
@Path("jakartaee10")
public class JakartaEE10Resource {
@GET
public Response ping(){
return Response
.ok("ping Jakarta 10")
.build();
}
}
When the URI to the service is visited, the message "ping Jakarta 10"
will be
displayed. The resource method can optionally include a @Path
annotation,
specifying a custom path for accessing the endpoint. If more than one method
annotated with @GET
is specified within the same resource class, then one of
them must specify a string-based path in order to differentiate. If
@Path("/ping")
were applied to the ping()
method, then the URI to access the
endpoint would change to the following:
http://localhost:port/HelloWorld/resources/jakartaee10/ping
In the example above, a return type of jakarta.ws.rs.core.Response
is returned
from the ping()
method. Returning a Response type enables an HTTP response to
be returned to the caller, indicating success or failure of a service call.
For instance, the following conditional will return an OK
or FAILURE
status
depending upon a condition:
if (valid) {
return Response.ok("Successful").build();
} else {
return Response.getStatus();
}
Although an HTTP response can be nice to receive, it is possible to return
different types of data from a web service, such as a plain text or JSON. By
default, Jakarta REST should negotiate with the client to determine the type of
data to return. However, to explicitly specify a type of data to be returned,
the @Produces
annotation can be applied to the resource method and a
jakarta.ws.rs.core.MediaType
can be applied. Applying following annotations
to an resource method would result in a JSON response at the URI
http://localhost:port/HelloWorld/resources/jakartaee10/json :
@GET
@Path("/json")
@Produces(MediaType.APPLICATION_JSON)
Jakarta REST contains annotations for each of the common other HTTP methods:
@PUT
, @POST
, @DELETE
, @PATCH
, @HEAD
, and @OPTIONS
. The annotation
@POST
is used to pass information to a web service resource. One can pass
information to a web service resource in a variety of ways, and in a variety of
formats. In most cases, Jakarta REST will negotiate with the client to
automatically determine the type of data being passed into a service. However,
in some cases it may be suitable to explicitly specify the type being consumed
by the service by specifying the @Consumes
annotation and passing a
jakarta.ws.rs.core.MediaType
. For instance, if a JSON payload is being passed
to a web service resource in order to update a database record, the @POST
annotation can be applied to the method.
@Path("/postMessage")
@POST
public String updateService(Message message) {...}
There are various ways to pass parameters to a web service resource. They
differ in the way that they are passed via the URI. A path parameter can be
specified within the @Path
by enclosing the parameter name within curly
braces {}
. If a parameter is passed in this manner, then it must be explicitly
specified within the web service resource method signature by specifying
@PathParam
and passing the String
based variable name. A web service
resource method can accept zero or more parameters in this manner. In the
following example, the helloService
accepts a name as a path parameter:
@GET
@Path("/hello/{name}")
public String helloService(@PathParam("name") String name){
return "Hello " + name;
}
A query parameter can also be passed via the URI by adding a question mark
character (?
) at the end of the URI and explicitly delimiting each parameter
with an ampersand (&
) character. Query parameters are specified in format
parameter_name=parameter_value
. In this way, the @Path
designation does not
contain any variables, but the web service resource method must contain each
query parameter by specifying the @QueryParam
annotation and providing the name
of the query parameter. For instance, to specify name from the example above
as a query parameter, the URI would be
http://localhost:port/HelloWorld/resources/hello?name=Josh
@GET
@Path("/hello")
public String helloServiceQueryParams(@QueryParam("name") String name){
return "Hello " + name;
}
Oftentimes web forms contain a large number of fields that need to be submitted
for processing. The values from these fields could be passed to a web service
resource using an HTML form and corresponding @FormParam
parameters within the
web service resource method definition. The @FormParam
annotation works very
similar to the @QueryParam
, except that it reads the parameters submitted via
an HTML form. The following demonstrates an HTML form that will submit to the
helloService
resource, passing a parameter.
<html>
<head>
<title>Hello Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<form action="/resources/jakartaee10/helloForm">
<p>
What is your name: <input type="text" name="name" />
<input type="submit" value="Say Hello" />
</form>
</body>
</html>
The associated web service resource should include @FormParam
as follows:
@POST
@Path("/helloForm")
public String helloFormParams(@FormParam("name") String name){
return "Hello " + name;
}
Jakarta REST includes a client API that can be used for calling upon web
service resources to obtain data, and passing data to services. The API is high
level and allows easy access, but it also includes some lower level features
for configuration, if needed. Most of the client API resides within the
jakarta.ws.rs.client
package, and the jakarta.ws.rs.client.ClientBuilder
is
a resource that is required for creating a new jakarta.ws.rs.client.Client
.
The lifecycle of a client is as follows:
Client
WebTarget
WebTarget
The following code demonstrates this workflow to call upon the HelloWorld jakartaee10
endpoint:
Client client = ClientBuilder.newClient();
Response res = client.target("http://localhost:8080/HelloWorld/resources/jakartaee10")
.request("text/plain").get();
System.out.println("Status + " + res.getStatus());
The client enables chaining of methods using a builder pattern to perform
tasks such as setting properties for a Client
, passing parameters to a
service, and so forth.
Response res = client.target("http://localhost:8080/HelloWorld/resources/jakartaee10/hello")
.queryParam("name", "Duke")
.request("text/plain").get();
The use of WebTarget
enables the compilation of complex web service endpoints.
Using a builder pattern, a complex URI can be constructed by adding path
segments, as needed. For instance, a base WebTarget
can be created, and then
paths can be added to it by calling upon the WebTarget
path()
method and
passing String
based path segments as follows:
WebTarget base = client.target("http://localhost:8080/HelloWorld/resources/jakartaee10");
Response response = base.path("hello").path("Duke")
.queryParam("name", "Duke")
.request("text/plain").get();
System.out.println("Status + " + response.readEntity(String.class));
There are more features available using Jakarta REST clients. To learn additional information please refer to the specification documentation.
Jakarta REST is a mature specification, and as such, it contains a number of
features that provide advanced configuration and use of RESTful web services
enabling flexibility and extensibility. One such feature is called a
“provider”, and providers enable the use of cross cutting actions within
Jakarta REST. A provider can be used to take a specific action based upon an
event or a type action that occurs when a service resource is invoked. For
instance, a provider can be used to automatically convert an HTTP payload to a
Java object, or vice versa. Providers can be automatically registered with an
application by specifying the @Provider
annotation on the provider class
implementation, or they can be manually registered.
Jakarta REST contains a number of default providers that can be used out of the box. Two such providers that are oftentimes used are filters and interceptors. Filters enable cross cutting actions to take place such as automatic logging or request validation, when certain events occur. There is a way to prioritize which filters are invoked and also to specify ordering of invocations. Interceptors also are initiated in a similar manner as filters, but the primary use of interceptors is to intercept requests and manipulate HTTP payloads.
Asynchronous processing can provide the end user with a better experience, as
it can greatly improve the performance of an application. Jakarta REST
provides asynchronous processing for both the client and the server. On the
server, asynchronous processing enables the resource method to send a message
to Jakarta REST to indicate that a response is forthcoming at some point in the
future. This allows the client to suspend the connection, perform other tasks,
and then resume the connection to check back on the pending future response
occasionally. In a similar manner, the client API can request an async
response from a web service, returning a Future
object. The Future
can then be
checked upon and process a response once it returns.
Server sent events provide a one-way communication based on the HTTP protocol
from the server to the client. The connection is long-running and remains
open, enabling multiple messages to be sent. Server sent events include both a
Client and a Server API. The Client API uses an SseEventSource
object to
register an event consumer to perform some action on an event. The Server API
uses the @Produces
annotation to indicate that MediaType.SERVER_SENT_EVENTS
will be produced by the web service resource. An object known as an
SseEventSink
along with an Sse
object are injected into the method, and they
enable the server to send multiple messages to the client using an open
text/event-stream
. A SseBroadcaster
can be created by calling upon
Sse.newBroadcaster()
, and it provides the ability to broadcast a message to all
registered consumers.
Jakarta REST provides an easy-to-use API for developing RESTful web services
for Jakarta EE. REST can be configured by adding an Application
class and
specifying a root path which can be used to access web service resources. The
@Path
annotation can be placed on a class to designate it as a Jakarta REST
resource, and methods annotated with @GET
, @POST
, or other HTTP request
types can be used to create web service resources. Web services can be used to
produce or consume data. There is also a full featured client available with
Jakarta REST, as well as advanced features such as asynchronous invocation and
server sent events.