Jakarta REST resources
Servlets give full control over HTTP, but for an API that is too low a level: addresses and parameters have to be parsed by hand. Jakarta REST (formerly JAX-RS) lets you describe an API with annotations. A class that serves a group of addresses is called a resource, and its methods are request handlers.
Enabling REST
First you need a class that enables Jakarta REST and sets the common address prefix. The Open Liberty generator creates it for you; in our package it looks like this:
// src/main/java/com/example/blog/RestApplication.java
package com.example.blog;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
@ApplicationPath("/api")
public class RestApplication extends Application {
}The class is empty: the server finds all resources in the application by itself. The @ApplicationPath("/api") annotation means that API addresses start with http://localhost:8080/blog/api.
The first resource
Create the file src/main/java/com/example/blog/PostResource.java:
// src/main/java/com/example/blog/PostResource.java
package com.example.blog;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/posts")
public class PostResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String list() {
return "List of posts";
}
}@Path("/posts") binds the class to the /api/posts address. @GET says the method answers GET requests, and @Produces says what content type it returns. Jakarta REST writes the string returned by the method into the response body.
curl -i http://localhost:8080/blog/api/postsHTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Content-Length: 13
List of posts
Method annotations
| Annotation | HTTP method | Typical action |
|---|---|---|
@GET | GET | Read data |
@POST | POST | Create a record |
@PUT | PUT | Replace a record |
@PATCH | PATCH | Change part of a record |
@DELETE | DELETE | Delete a record |
@Path can also go on a method — then its path is appended to the class path. A method with @Path("/latest") in our class answers /api/posts/latest.
Content types
| Constant | Value |
|---|---|
MediaType.TEXT_PLAIN | text/plain |
MediaType.TEXT_HTML | text/html |
MediaType.APPLICATION_JSON | application/json |
@Produces can be put on the whole class — then it applies to all methods. For the blog API it will be APPLICATION_JSON once we start returning data in the next lessons.
Servlet or resource
| Servlet | Jakarta REST resource |
|---|---|
| One class per address | Many addresses in one class |
| Parameters are read by hand | Parameters arrive as method arguments |
| JSON is built by hand | Objects become JSON automatically |
For an API you almost always pick resources. Servlets remain for special cases: serving files, filters, low-level stream handling.
Common mistake
Forgetting the class with @ApplicationPath. Then Jakarta REST is not enabled in the application, and the server looks for a plain file at /api/posts:
Error 404: jakarta.servlet.ServletException: java.io.FileNotFoundException: SRVE0190E: File not found: /api/posts
If every API address answers 404, check the RestApplication class first.