How to Use Jersey Client to Call REST Services in Java

The Jersey Client API is the reference implementation of the JAX-RS 2.x/3.x client specification. It provides a fluent, type-safe way to consume REST endpoints from any Java application — no framework required beyond Jersey itself. In this guide you will learn how to perform every HTTP method, pass headers and query parameters, consume and produce JSON, add Basic and Bearer token authentication, and handle errors gracefully.

Maven Dependencies

<!-- Jersey client + Jackson JSON provider -->
<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>3.1.5</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>3.1.5</version>
</dependency>
<!-- Required HK2 injection bridge -->
<dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-hk2</artifactId>
    <version>3.1.5</version>
</dependency>

Creating a Client Instance

A Client instance is expensive to create — create it once and reuse it across requests, just like a connection pool:

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.MediaType;

// Create once, reuse everywhere
Client client = ClientBuilder.newClient();

// Register Jackson for JSON
Client jsonClient = ClientBuilder.newBuilder()
    .register(org.glassfish.jersey.jackson.JacksonFeature.class)
    .build();

// Remember to close when done (e.g. app shutdown)
// client.close();

GET Request — Retrieve a Resource

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

public class GetExample {
    public static void main(String[] args) {
        Client client = ClientBuilder.newClient();

        // Simple GET — returns plain String
        String body = client
            .target("https://jsonplaceholder.typicode.com")
            .path("/posts/{id}")
            .resolveTemplate("id", 1)              // replaces {id} with 1
            .request(MediaType.APPLICATION_JSON)
            .get(String.class);

        System.out.println(body);

        // GET with query parameters
        Response response = client
            .target("https://jsonplaceholder.typicode.com/posts")
            .queryParam("userId", 1)
            .queryParam("_limit", 5)
            .request(MediaType.APPLICATION_JSON)
            .get();

        System.out.println("Status : " + response.getStatus());
        System.out.println("Body   : " + response.readEntity(String.class));
        response.close();

        client.close();
    }
}

POST Request — Create a Resource

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

public class PostExample {

    record Post(int userId, String title, String body) {}

    public static void main(String[] args) {
        Client client = ClientBuilder.newBuilder()
            .register(org.glassfish.jersey.jackson.JacksonFeature.class)
            .build();

        Post newPost = new Post(1, "Jersey Client Tutorial", "Learn Jersey client step by step.");

        Response response = client
            .target("https://jsonplaceholder.typicode.com/posts")
            .request(MediaType.APPLICATION_JSON)
            .post(Entity.json(newPost));          // serialises record to JSON

        System.out.println("Created: HTTP " + response.getStatus()); // 201
        System.out.println(response.readEntity(String.class));
        response.close();
        client.close();
    }
}

PUT and DELETE Requests

// PUT — full update
Response putResp = client
    .target("https://jsonplaceholder.typicode.com/posts/1")
    .request(MediaType.APPLICATION_JSON)
    .put(Entity.json(new Post(1, "Updated Title", "Updated body.")));
System.out.println("PUT: HTTP " + putResp.getStatus());  // 200
putResp.close();

// PATCH — partial update
Response patchResp = client
    .target("https://jsonplaceholder.typicode.com/posts/1")
    .request(MediaType.APPLICATION_JSON)
    .method("PATCH", Entity.json("{"title":"Patched title"}"));
System.out.println("PATCH: HTTP " + patchResp.getStatus());
patchResp.close();

// DELETE
Response deleteResp = client
    .target("https://jsonplaceholder.typicode.com/posts/1")
    .request()
    .delete();
System.out.println("DELETE: HTTP " + deleteResp.getStatus());  // 200
deleteResp.close();

Adding Request Headers

Response resp = client
    .target("https://api.example.com/data")
    .request(MediaType.APPLICATION_JSON)
    .header("X-Request-ID", "abc-123")           // custom header
    .header("Accept-Language", "en-US")           // locale hint
    .header("Authorization", "Bearer eyJ...")
    .get();

Authentication

import java.nio.charset.StandardCharsets;
import java.util.Base64;

// HTTP Basic Auth
String credentials = Base64.getEncoder()
    .encodeToString("alice:s3cr3t".getBytes(StandardCharsets.UTF_8));

Response basicResp = client
    .target("https://api.example.com/secure")
    .request()
    .header("Authorization", "Basic " + credentials)
    .get();

// Bearer Token (JWT)
String jwt = "eyJhbGciOiJIUzI1NiJ9...";
Response jwtResp = client
    .target("https://api.example.com/secure")
    .request()
    .header("Authorization", "Bearer " + jwt)
    .get();

Error Handling

import jakarta.ws.rs.core.Response.Status.Family;

public static void safeGet(Client client, String url) {
    Response response = client
        .target(url)
        .request(MediaType.APPLICATION_JSON)
        .get();

    try {
        if (response.getStatusInfo().getFamily() == Family.SUCCESSFUL) {
            System.out.println("OK: " + response.readEntity(String.class));
        } else if (response.getStatus() == 404) {
            System.out.println("Resource not found: " + url);
        } else if (response.getStatus() == 401) {
            System.out.println("Unauthorized — check credentials");
        } else {
            System.out.println("Error HTTP " + response.getStatus() +
                ": " + response.readEntity(String.class));
        }
    } finally {
        response.close();   // always close to return connection to pool
    }
}

Configuring Timeouts

import java.util.concurrent.TimeUnit;
import org.glassfish.jersey.client.ClientProperties;

Client client = ClientBuilder.newBuilder()
    .connectTimeout(5,  TimeUnit.SECONDS)   // fail-fast if server unreachable
    .readTimeout(30, TimeUnit.SECONDS)      // max wait for response body
    .build();

Method Quick Reference

MethodJersey CallTypical Status
GET.get() / .get(Type.class)200
POST.post(Entity.json(obj))201
PUT.put(Entity.json(obj))200
PATCH.method("PATCH", Entity.json(obj))200
DELETE.delete()200 / 204
HEAD.head()200 (no body)
OPTIONS.options()200

See Also

Conclusion

The Jersey Client API’s fluent builder pattern makes consuming REST services clean and readable. Create one Client instance per application, configure connect and read timeouts upfront, always close Response objects in a finally block or try-with-resources, and register JacksonFeature once for automatic JSON serialisation. These habits keep your REST client performant and leak-free in production.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.