Return to site

🌐🧩 RESTFUL WEB SERVICES WITH JAX-RS (JAKARTA REST)

· jakartaee

🔸 TLDR

▪️ JAX-RS (Jakarta REST) lets you build clean REST APIs with annotations (@Path, @GET, @POST…), consume them with a typed client API, handle query/path params safely, and even stream updates with Server-Sent Events (SSE). 🚀

Section image

🔸 SIMPLE RESTFUL WEB SERVICE

▪️ Define a resource with @Path + HTTP method annotations

▪️ Configure the application entry point with @ApplicationPath

▪️ Serialize/deserialize data (Java ↔ XML) with JAXB (and often JSON too)

▪️ Test quickly with curl / Postman / integration tests ✅

import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
@Produces(MediaType.TEXT_PLAIN)
public class HelloResource {

  @GET
  public String hello(@QueryParam("name") @DefaultValue("world") String name) {
    return "Hello " + name;
  }
} 
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

@ApplicationPath("/api")
public class RestApp extends Application {
  // empty is fine: auto-discovery by container
}

✅ Quick test:

curl "http://localhost:8080/myapp/api/hello?name=Vincent"

🔸 CONVERTING DATA BETWEEN JAVA AND XML WITH JAXB

▪️ JAXB uses annotations like @XmlRootElement to map Java objects to XML : https://jakarta.ee/specifications/xml-binding/2.3/apidocs/javax/xml/bind/annotation/xmlrootelement

▪️ Works great for legacy integrations & enterprise APIs 🏢

import jakarta.xml.bind.annotation.*;

@XmlRootElement(name = "user")
@XmlAccessorType(XmlAccessType.FIELD)
public class User {
  public Long id;
  public String name;

  public User() {}
  public User(Long id, String name) { this.id = id; this.name = name; }
} 
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;

@Path("/users")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public class UserResource {

  @GET
  @Path("/{id}")
  public User get(@PathParam("id") long id) {
    return new User(id, "Ada");
  }
}

🔸 RESTFUL WEB SERVICE CLIENT (JAX-RS CLIENT API)

▪️ Use ClientBuilder + WebTarget to call APIs

▪️ You can send headers, JSON/XML bodies, handle status codes, etc. 🧰

import jakarta.ws.rs.client.*;
import jakarta.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();

String txt = client
  .target("http://localhost:8080/myapp/api/hello")
  .queryParam("name", "Vincent")
  .request(MediaType.TEXT_PLAIN)
  .get(String.class);

System.out.println(txt);

🔸 QUERY & PATH PARAMETERS

▪️ Server side: @QueryParam, @PathParam, @DefaultValue

▪️ Client side: queryParam() and resolveTemplate() (safe path replacement) 🔒

Server

@Path("/orders")
public class OrderResource {

  @GET
  @Path("/{id}")
  @Produces(MediaType.APPLICATION_JSON)
  public String getOrder(
      @PathParam("id") String id,
      @QueryParam("verbose") @DefaultValue("false") boolean verbose
  ) {
    return "{\"id\":\"" + id + "\",\"verbose\":" + verbose + "}";
  }
}

Client

import jakarta.ws.rs.client.*;
import jakarta.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();

String json = client
  .target("http://localhost:8080/myapp/api")
  .path("/orders/{id}")
  .resolveTemplate("id", "A-42")
  .queryParam("verbose", true)
  .request(MediaType.APPLICATION_JSON)
  .get(String.class);

System.out.println(json);

🔸 SERVER-SENT EVENTS (SSE)

▪️ SSE = one-way stream from server ➜ client over HTTP (perfect for live updates) 📡

▪️ Great for dashboards, notifications, progress updates… without WebSockets.

Server (push events)

import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.sse.*;

@Path("/stream")
public class SseResource {

  @GET
  @Produces(MediaType.SERVER_SENT_EVENTS)
  public void stream(@Context SseEventSink sink, @Context Sse sse) {
    for (int i = 1; i <= 5; i++) {
      OutboundSseEvent event = sse.newEventBuilder()
          .name("tick")
          .data(String.class, "event #" + i)
          .build();
      sink.send(event);
    }
    sink.close();
  }
}

Client (listen to events)

import jakarta.ws.rs.client.*;
import jakarta.ws.rs.sse.*;

Client client = ClientBuilder.newBuilder().build();
WebTarget target = client.target("http://localhost:8080/myapp/api/stream");

try (SseEventSource source = SseEventSource.target(target).build()) {
  source.register(
      (InboundSseEvent e) -> System.out.println("SSE: " + e.readData()),
      (Throwable t) -> t.printStackTrace(),
      () -> System.out.println("SSE closed")
  );
  source.open();
  Thread.sleep(2000); // demo wait
}

🔸 TAKEAWAYS

▪️ JAX-RS keeps REST code tiny + readable with annotations ✨

▪️ JAXB makes XML interop painless for enterprise/legacy needs 🧾

▪️ The JAX-RS client API gives you a first-class way to call services 🔁

▪️ Query + path params are safe & explicit (less string concatenation!) ✅

▪️ SSE is the simplest “real-time-ish” option when you only need server ➜ client 📣

#Java #JakartaEE #JAXRS #REST #Backend #APIs #Microservices #SSE #JAXB #WebDevelopment #SoftwareEngineering

Go further with Java certification:

Java👇

Spring👇

SpringBook👇

JavaBook👇