Java SDK best practices

Ask about this Page
Copy for LLM
View as Markdown

Recommended practices for configuring, running, and maintaining the Java SDK.

Keep the SDK up to date

Always use a recent version of the SDK to ensure you have the latest features, performance improvements, and security fixes.

To stay informed about new releases:

Store credentials securely

Never hardcode credentials such as clientId and clientSecret in your source code. Always load them from environment variables or a secrets management service at runtime.
Load credentials from environment variablesjava
String clientId = System.getenv("CTP_CLIENT_ID");
String clientSecret = System.getenv("CTP_CLIENT_SECRET");
String projectKey = System.getenv("CTP_PROJECT_KEY");

ProjectApiRoot apiRoot = ApiRootBuilder.of()
  .defaultClient(
    ClientCredentials.of()
      .withClientId(clientId)
      .withClientSecret(clientSecret)
      .build(),
    ServiceRegion.GCP_EUROPE_WEST1
  )
  .build(projectKey);

Reuse the API client

The ProjectApiRoot (and equivalent root objects for other APIs) is thread-safe and designed to be created once and reused across your application. Creating a new client per request is wasteful. Each client holds its own thread pool and connection pool.

Create a single instance and inject or share it through your application:

Create the API client once at application startupjava
ProjectApiRoot apiRoot = ApiRootBuilder.of()
  .defaultClient(
    ClientCredentials.of()
      .withClientId(System.getenv("CTP_CLIENT_ID"))
      .withClientSecret(System.getenv("CTP_CLIENT_SECRET"))
      .build(),
    ServiceRegion.GCP_EUROPE_WEST1
  )
  .build(System.getenv("CTP_PROJECT_KEY"));

// Reuse apiRoot throughout the application lifetime
For Spring applications, declare the client as a @Bean so the framework manages its lifecycle.

Close the client

The Java SDK client holds resources including thread pools and IO connections. The ApiRoot classes implement the Closeable interface and must be closed when your application shuts down.

Explicit close

Call close() explicitly when your application shuts down:
Close the API clientjava
// Close the client to release thread pools and IO connections
apiRoot.getApiHttpClient().close();
For Spring, use @PreDestroy or register a shutdown hook:
Close the API client with @PreDestroyjava
@PreDestroy
public void closeClient() {
  apiRoot.getApiHttpClient().close();
}

try-with-resources

For short-lived operations (such as scripts or batch jobs), use a try-with-resources block to automatically close the client:

Close the API client with try-with-resourcesjava
try (ProjectApiRoot apiRoot = ApiRootBuilder.of()
  .defaultClient(
    ClientCredentials.of()
      .withClientId(System.getenv("CTP_CLIENT_ID"))
      .withClientSecret(System.getenv("CTP_CLIENT_SECRET"))
      .build(),
    ServiceRegion.GCP_EUROPE_WEST1
  )
  .build(System.getenv("CTP_PROJECT_KEY"))) {

  // Perform operations
  Project project = apiRoot.get().executeBlocking().getBody();
  System.out.println(project.getKey());

} // client is automatically closed here

Troubleshooting

ApiHttpResponse.getMessage() returns HTTP status text

ApiHttpResponse is an abstraction over the raw HTTP transfer. Its getMessage() method returns the HTTP status reason phrase (such as OK, Bad Request, or Not Found), not the response body.
When a request fails, the ErrorMiddleware throws an exception whose message contains the HTTP body. The thrown exceptions extend ApiHttpException, which provides a getBodyAs() helper to deserialize the error body:
Handle API errorsjava
apiRoot.products().post(draft).execute()
  .exceptionally(throwable -> {
    if (throwable instanceof BadRequestException) {
      // BadRequestException and ConcurrentModificationException automatically
      // deserialize the error response
      String message = ((BadRequestException) throwable)
        .getErrorResponse()
        .getMessage();
    }
    if (throwable instanceof ApiHttpException) {
      // For all other API errors, use getBodyAs() to deserialize manually
      String message = ((ApiHttpException) throwable)
        .getBodyAs(ErrorResponse.class)
        .getMessage();
    }
    return null;
  });

Further resources