Latest commit

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..

README.md

HTTP Client

A powerful and flexible HTTP client library for Java projects, built on top of Apache HttpComponents. This library provides a clean, fluent API for making HTTP requests with support for retries, OAuth authentication, custom handlers, and comprehensive logging.

Features

  • 🌐 Full HTTP Support - GET, POST, PUT, DELETE, and PATCH methods
  • 🔄 Retry Mechanism - Configurable retry policies with backoff strategies
  • 🔐 Authentication - Built-in support for Basic Auth and OAuth 1.0
  • 📝 Multiple Payload Types - JSON, Form data, Multipart, and String entities
  • 🎯 Request/Response Handlers - Extensible hooks for request and response processing
  • 📊 Structured Logging - Logstash integration for detailed request/response logging
  • ⚙️ Flexible Configuration - Custom headers, query parameters, and execution context
  • 🛠️ Error Handling - Comprehensive exception handling and retry mechanisms

Installation

Gradle

dependencies {
implementation 'com.javaquery:httpclient:1.0.7'
}

Maven

<dependency>
<groupId>com.javaquery</groupId>
<artifactId>httpclient</artifactId>
<version>1.0.7</version>
</dependency>

Quick Start

Simple GET Request

importcom.javaquery.http.*;
importcom.javaquery.http.handler.HttpResponseHandler;
// Build the requestHttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("GetUsers", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.build();
// Create execution contextHttpExecutionContextcontext = newHttpExecutionContext();
// Execute requestHttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
});

POST Request with JSON Payload

StringjsonPayload = "{\"name\":\"John Doe\",\"email\":\"john@example.com\"}";
HttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("CreateUser", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withHeader("Content-Type", "application/json")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8, "application/json", jsonPayload
))
.build();
HttpExecutionContextcontext = newHttpExecutionContext();
HttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<JSONObject>() {
@OverridepublicJSONObjectonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getJSONObjectBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
System.err.println("Max retries reached");
}
});

HTTP Methods

GET Request

HttpRequestgetRequest = newHttpRequest.HttpRequestBuilder("GetRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withQueryParameter("page", "1")
.withQueryParameter("size", "20")
.build();

POST Request with Form Data

Map<String, Object> formData = newHashMap<>();
formData.put("username", "john.doe");
formData.put("email", "john@example.com");
HttpRequestpostRequest = newHttpRequest.HttpRequestBuilder("PostForm", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/submit")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
))
.build();

POST Request with Multipart File Upload

Map<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document upload");
HttpRequestuploadRequest = newHttpRequest.HttpRequestBuilder("FileUpload", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/upload")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
))
.build();

PUT Request

StringupdatePayload = "{\"status\":\"active\"}";
HttpRequestputRequest = newHttpRequest.HttpRequestBuilder("UpdateUser", HttpMethod.PUT)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
updatePayload
))
.build();

DELETE Request

HttpRequestdeleteRequest = newHttpRequest.HttpRequestBuilder("DeleteUser", HttpMethod.DELETE)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.build();

Authentication

Basic Authentication

HttpRequestauthRequest = newHttpRequest.HttpRequestBuilder("SecureEndpoint", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/secure")
.withBasicAuth("username", "password")
.build();

OAuth 1.0

importcom.javaquery.http.oauth.OAuthConfig;
OAuthConfigoauthConfig = OAuthConfig.builder()
.consumerKey("your-consumer-key")
.consumerSecret("your-consumer-secret")
.accessToken("your-access-token")
.accessTokenSecret("your-access-token-secret")
.build();
HttpRequestoauthRequest = newHttpRequest.HttpRequestBuilder("OAuthRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/oauth/resource")
.build();
// Add OAuth handler to execution contextHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newOAuth10HttpRequestHandler(oauthConfig));
httpClient.execute(context, oauthRequest, responseHandler);

Headers and Query Parameters

Adding Headers

// Single headerHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeader("Authorization", "Bearer token123")
.withHeader("X-Custom-Header", "value")
.build();
// Multiple headersMap<String, String> headers = newHashMap<>();
headers.put("Content-Type", "application/json");
headers.put("Accept", "application/json");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeaders(headers)
.build();

Adding Query Parameters

// Single parameterHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/search")
.withQueryParameter("q", "java")
.withQueryParameter("limit", "10")
.build();
// Multiple parametersMap<String, String> params = newHashMap<>();
params.put("page", "1");
params.put("size", "20");
params.put("sort", "name");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withQueryParameter(params)
.build();

Retry Policies

Default Retry Policy

importcom.javaquery.http.DefaultRetryPolicy;
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("RetryRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/unstable")
.withRetryPolicy(DefaultRetryPolicy.get(3)) // Retry up to 3 times
.build();

Custom Retry Policy

importcom.javaquery.http.retry.*;
RetryPolicycustomRetry = newRetryPolicy(
newDefaultRetryCondition(), // When to retrynewDefaultBackoffStrategy(), // How long to wait between retries5// Max retry attempts
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("CustomRetry", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withRetryPolicy(customRetry)
.build();

Implementing Custom Retry Condition

importcom.javaquery.http.retry.RetryCondition;
publicclassCustomRetryConditionimplementsRetryCondition {
@OverridepublicbooleanshouldRetry(HttpRequestResponsehttpRequestResponse) {
HttpResponseresponse = httpRequestResponse.getHttpResponse();
// Retry on 5xx errors or specific 4xx errorsintstatusCode = response.getStatusCode();
returnstatusCode >= 500 || statusCode == 429 || statusCode == 408;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newCustomRetryCondition(),
newDefaultBackoffStrategy(),
3
);

Implementing Custom Backoff Strategy

importcom.javaquery.http.retry.BackoffStrategy;
publicclassExponentialBackoffimplementsBackoffStrategy {
@OverridepubliclongcomputeDelayBeforeNextRetry(HttpRequestResponsehttpRequestResponse, intretriesAttempted) {
// Exponential backoff: 2^attempt * 1000msreturn (long) Math.pow(2, retriesAttempted) * 1000;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newExponentialBackoff(),
5
);

Request and Response Handlers

Custom Request Handler

importcom.javaquery.http.handler.HttpRequestHandler;
publicclassCustomHeaderHandlerimplementsHttpRequestHandler {
@OverridepublicvoidonRequest(HttpExecutionContextcontext, HttpRequesthttpRequest) {
// Add custom headers before each requesthttpRequest.addHeader("X-Request-ID", UUID.randomUUID().toString());
httpRequest.addHeader("X-Timestamp", String.valueOf(System.currentTimeMillis()));
}
}
// Use the handlerHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newCustomHeaderHandler());
httpClient.execute(context, httpRequest, responseHandler);

Response Handler

importcom.javaquery.http.handler.HttpResponseHandler;
HttpResponseHandler<User> userHandler = newHttpResponseHandler<User>() {
@OverridepublicUseronResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() == 200) {
JSONObjectjson = httpResponse.getJSONObjectBody();
returnparseUser(json);
} elseif (httpResponse.getStatusCode() == 404) {
thrownewUserNotFoundException("User not found");
} else {
thrownewHttpException("Unexpected status: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Failed after maximum retry attempts. Status: {}", httpResponse.getStatusCode());
}
privateUserparseUser(JSONObjectjson) {
// Parse JSON to User objectreturnUser.builder()
.id(json.getLong("id"))
.name(json.getString("name"))
.email(json.getString("email"))
.build();
}
};

Execution Context

The HttpExecutionContext allows you to pass metadata and configure handlers for request execution.

Using Metadata

HttpExecutionContextcontext = newHttpExecutionContext();
// Add metadataMap<String, Object> metadata = newHashMap<>();
metadata.put("userId", "12345");
metadata.put("requestSource", "mobile-app");
context.setMetaData(metadata);
// Add individual metadatacontext.addMetaData("correlationId", UUID.randomUUID().toString());
httpClient.execute(context, httpRequest, responseHandler);

Multiple Request Handlers

HttpExecutionContextcontext = newHttpExecutionContext();
// Add multiple handlerscontext.addHttpRequestHandler(newAuthHeaderHandler());
context.addHttpRequestHandler(newLoggingHandler());
context.addHttpRequestHandler(newMetricsHandler());
// Or set all at onceList<HttpRequestHandler> handlers = Arrays.asList(
newAuthHeaderHandler(),
newLoggingHandler(),
newMetricsHandler()
);
context.setHttpRequestHandlers(handlers);
httpClient.execute(context, httpRequest, responseHandler);

Response Processing

Working with HTTP Response

HttpResponseHandler<Object> handler = newHttpResponseHandler<Object>() {
@OverridepublicObjectonResponse(HttpResponsehttpResponse) {
// Get status codeintstatusCode = httpResponse.getStatusCode();
// Get headersMap<String, String> headers = httpResponse.getHeaders();
StringcontentType = headers.get("Content-Type");
// Get response body as stringStringbody = httpResponse.getBody();
// Parse as JSON ObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
// Parse as JSON ArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
returnbody;
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
};

JSON Response Parsing

// Parse as JSONObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
Stringname = jsonObject.getString("name");
intage = jsonObject.getInt("age");
// Parse as JSONArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
for (inti = 0; i < jsonArray.length(); i++) {
JSONObjectitem = jsonArray.getJSONObject(i);
// Process each item
}

Advanced Usage

Complete Example with All Features

importcom.javaquery.http.*;
importcom.javaquery.http.handler.*;
importcom.javaquery.http.retry.*;
publicclassAdvancedHttpClientExample {
publicstaticvoidmain(String[] args) {
// Build request with all optionsMap<String, String> headers = newHashMap<>();
headers.put("Authorization", "Bearer token123");
headers.put("Accept", "application/json");
Map<String, String> queryParams = newHashMap<>();
queryParams.put("page", "1");
queryParams.put("size", "20");
Stringpayload = "{\"action\":\"update\",\"data\":{\"status\":\"active\"}}";
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newDefaultBackoffStrategy(),
3
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("ComplexRequest", HttpMethod.POST)
.withHost("https://api.example.com")
.withPort(443)
.withEndPoint("/api/v1/resources")
.withHeaders(headers)
.withQueryParameter(queryParams)
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
payload
))
.withRetryPolicy(retryPolicy)
.build();
// Setup execution contextHttpExecutionContextcontext = newHttpExecutionContext();
Map<String, Object> metadata = newHashMap<>();
metadata.put("correlationId", UUID.randomUUID().toString());
metadata.put("requestSource", "backend-service");
context.setMetaData(metadata);
context.addHttpRequestHandler(newHttpRequestHandler() {
@OverridepublicvoidonRequest(HttpExecutionContextctx, HttpRequestreq) {
// Add request timestampreq.addHeader("X-Request-Timestamp", String.valueOf(System.currentTimeMillis()));
}
});
// Execute requestHttpClienthttpClient = newHttpClient();
Resultresult = httpClient.execute(context, request, newHttpResponseHandler<Result>() {
@OverridepublicResultonResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() >= 200 && httpResponse.getStatusCode() < 300) {
returnparseResult(httpResponse.getJSONObjectBody());
} else {
thrownewHttpException("Request failed: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Max retries reached. Status: {}", httpResponse.getStatusCode());
// Send alert, log to monitoring system, etc.
}
}
);
}
privatestaticResultparseResult(JSONObjectjson) {
// Parse JSON to Result objectreturnnewResult(json);
}
}

Handling Different Content Types

// JSON payloadHttpRequest.HttpPayloadjsonPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
"{\"key\":\"value\"}"
);
// Form dataMap<String, Object> formData = newHashMap<>();
formData.put("username", "john");
formData.put("password", "secret");
HttpRequest.HttpPayloadformPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
);
// Multipart form dataMap<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document");
HttpRequest.HttpPayloadmultipartPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
);
// Plain textHttpRequest.HttpPayloadtextPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"text/plain",
"Plain text content"
);
// XMLHttpRequest.HttpPayloadxmlPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/xml",
"<root><item>value</item></root>"
);

Error Handling

try {
httpClient.execute(context, request, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
intstatusCode = httpResponse.getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
returnhttpResponse.getBody();
} elseif (statusCode == 401) {
thrownewAuthenticationException("Authentication required");
} elseif (statusCode == 403) {
thrownewAuthorizationException("Access denied");
} elseif (statusCode == 404) {
thrownewResourceNotFoundException("Resource not found");
} elseif (statusCode >= 500) {
thrownewServerException("Server error: " + statusCode);
} else {
thrownewHttpException("HTTP error: " + statusCode);
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Log or alert when max retries exhaustedthrownewMaxRetriesExceededException(
"Failed after " + retryPolicy.getMaxErrorRetry() + " attempts"
);
}
});
} catch (AuthenticationExceptione) {
// Handle authentication error
} catch (ResourceNotFoundExceptione) {
// Handle not found
} catch (HttpExceptione) {
// Handle general HTTP errors
} catch (Exceptione) {
// Handle unexpected errors
}

Logging

The HTTP client uses SLF4J for logging and integrates with Logstash for structured logging. Request and response details are automatically logged with correlation information.

Enable Logging

Add to your logback.xml:

<configuration>
<appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender">
<encoderclass="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<loggername="com.javaquery.http"level="INFO" />
<rootlevel="INFO">
<appender-refref="CONSOLE" />
</root>
</configuration>

Logged information includes:

  • Request name and method
  • URL and endpoint
  • Headers and query parameters
  • Payload information
  • Response status code
  • Response time
  • Retry attempts
  • Metadata from execution context

API Reference

HttpRequest.HttpRequestBuilder

Builder for creating HTTP requests.

Methods:

  • withHost(String host) - Set the host URL
  • withPort(int port) - Set the port number
  • withEndPoint(String endPoint) - Set the endpoint path
  • withHeader(String key, String value) - Add a single header
  • withHeaders(Map<String, String> headers) - Add multiple headers
  • withQueryParameter(String key, String value) - Add a query parameter
  • withQueryParameter(Map<String, String> params) - Add multiple query parameters
  • withBasicAuth(String username, String password) - Set basic authentication
  • withHttpPayload(HttpPayload payload) - Set the request payload
  • withRetryPolicy(RetryPolicy policy) - Set retry policy
  • build() - Build the HttpRequest

HttpResponse

Response object containing status, headers, and body.

Methods:

  • int getStatusCode() - Get HTTP status code
  • Map<String, String> getHeaders() - Get response headers
  • String getBody() - Get response body as string
  • JSONObject getJSONObjectBody() - Parse body as JSON object
  • JSONArray getJSONArrayBody() - Parse body as JSON array

HttpClient

Main client for executing requests.

Methods:

  • <R> R execute(HttpExecutionContext context, HttpRequest request, HttpResponseHandler<R> handler) - Execute HTTP request

HttpExecutionContext

Context for request execution with metadata and handlers.

Methods:

  • void setMetaData(Map<String, Object> metaData) - Set metadata map
  • void addMetaData(String key, Object value) - Add single metadata entry
  • void addHttpRequestHandler(HttpRequestHandler handler) - Add request handler
  • void setHttpRequestHandlers(List<HttpRequestHandler> handlers) - Set multiple handlers

Requirements

  • Java 11 or higher
  • Apache HttpComponents 4.5.14
  • SLF4J 2.0.16
  • JSON 20250107
  • ScribeJava 8.3.3 (for OAuth)

Dependencies

This module depends on:

  • com.javaquery:util - Utility classes

License

This project is part of the JLite library suite.

Contributing

Contributions are welcome! Please ensure all tests pass before submitting pull requests.

Author

javaquery

Version

Current version: 1.0.7


For more information and updates, visit the JLite GitHub repository.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..

README.md

HTTP Client

A powerful and flexible HTTP client library for Java projects, built on top of Apache HttpComponents. This library provides a clean, fluent API for making HTTP requests with support for retries, OAuth authentication, custom handlers, and comprehensive logging.

Features

  • 🌐 Full HTTP Support - GET, POST, PUT, DELETE, and PATCH methods
  • 🔄 Retry Mechanism - Configurable retry policies with backoff strategies
  • 🔐 Authentication - Built-in support for Basic Auth and OAuth 1.0
  • 📝 Multiple Payload Types - JSON, Form data, Multipart, and String entities
  • 🎯 Request/Response Handlers - Extensible hooks for request and response processing
  • 📊 Structured Logging - Logstash integration for detailed request/response logging
  • ⚙️ Flexible Configuration - Custom headers, query parameters, and execution context
  • 🛠️ Error Handling - Comprehensive exception handling and retry mechanisms

Installation

Gradle

dependencies {
implementation 'com.javaquery:httpclient:1.0.7'
}

Maven

<dependency>
<groupId>com.javaquery</groupId>
<artifactId>httpclient</artifactId>
<version>1.0.7</version>
</dependency>

Quick Start

Simple GET Request

importcom.javaquery.http.*;
importcom.javaquery.http.handler.HttpResponseHandler;
// Build the requestHttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("GetUsers", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.build();
// Create execution contextHttpExecutionContextcontext = newHttpExecutionContext();
// Execute requestHttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
});

POST Request with JSON Payload

StringjsonPayload = "{\"name\":\"John Doe\",\"email\":\"john@example.com\"}";
HttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("CreateUser", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withHeader("Content-Type", "application/json")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8, "application/json", jsonPayload
))
.build();
HttpExecutionContextcontext = newHttpExecutionContext();
HttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<JSONObject>() {
@OverridepublicJSONObjectonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getJSONObjectBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
System.err.println("Max retries reached");
}
});

HTTP Methods

GET Request

HttpRequestgetRequest = newHttpRequest.HttpRequestBuilder("GetRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withQueryParameter("page", "1")
.withQueryParameter("size", "20")
.build();

POST Request with Form Data

Map<String, Object> formData = newHashMap<>();
formData.put("username", "john.doe");
formData.put("email", "john@example.com");
HttpRequestpostRequest = newHttpRequest.HttpRequestBuilder("PostForm", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/submit")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
))
.build();

POST Request with Multipart File Upload

Map<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document upload");
HttpRequestuploadRequest = newHttpRequest.HttpRequestBuilder("FileUpload", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/upload")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
))
.build();

PUT Request

StringupdatePayload = "{\"status\":\"active\"}";
HttpRequestputRequest = newHttpRequest.HttpRequestBuilder("UpdateUser", HttpMethod.PUT)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
updatePayload
))
.build();

DELETE Request

HttpRequestdeleteRequest = newHttpRequest.HttpRequestBuilder("DeleteUser", HttpMethod.DELETE)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.build();

Authentication

Basic Authentication

HttpRequestauthRequest = newHttpRequest.HttpRequestBuilder("SecureEndpoint", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/secure")
.withBasicAuth("username", "password")
.build();

OAuth 1.0

importcom.javaquery.http.oauth.OAuthConfig;
OAuthConfigoauthConfig = OAuthConfig.builder()
.consumerKey("your-consumer-key")
.consumerSecret("your-consumer-secret")
.accessToken("your-access-token")
.accessTokenSecret("your-access-token-secret")
.build();
HttpRequestoauthRequest = newHttpRequest.HttpRequestBuilder("OAuthRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/oauth/resource")
.build();
// Add OAuth handler to execution contextHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newOAuth10HttpRequestHandler(oauthConfig));
httpClient.execute(context, oauthRequest, responseHandler);

Headers and Query Parameters

Adding Headers

// Single headerHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeader("Authorization", "Bearer token123")
.withHeader("X-Custom-Header", "value")
.build();
// Multiple headersMap<String, String> headers = newHashMap<>();
headers.put("Content-Type", "application/json");
headers.put("Accept", "application/json");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeaders(headers)
.build();

Adding Query Parameters

// Single parameterHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/search")
.withQueryParameter("q", "java")
.withQueryParameter("limit", "10")
.build();
// Multiple parametersMap<String, String> params = newHashMap<>();
params.put("page", "1");
params.put("size", "20");
params.put("sort", "name");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withQueryParameter(params)
.build();

Retry Policies

Default Retry Policy

importcom.javaquery.http.DefaultRetryPolicy;
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("RetryRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/unstable")
.withRetryPolicy(DefaultRetryPolicy.get(3)) // Retry up to 3 times
.build();

Custom Retry Policy

importcom.javaquery.http.retry.*;
RetryPolicycustomRetry = newRetryPolicy(
newDefaultRetryCondition(), // When to retrynewDefaultBackoffStrategy(), // How long to wait between retries5// Max retry attempts
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("CustomRetry", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withRetryPolicy(customRetry)
.build();

Implementing Custom Retry Condition

importcom.javaquery.http.retry.RetryCondition;
publicclassCustomRetryConditionimplementsRetryCondition {
@OverridepublicbooleanshouldRetry(HttpRequestResponsehttpRequestResponse) {
HttpResponseresponse = httpRequestResponse.getHttpResponse();
// Retry on 5xx errors or specific 4xx errorsintstatusCode = response.getStatusCode();
returnstatusCode >= 500 || statusCode == 429 || statusCode == 408;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newCustomRetryCondition(),
newDefaultBackoffStrategy(),
3
);

Implementing Custom Backoff Strategy

importcom.javaquery.http.retry.BackoffStrategy;
publicclassExponentialBackoffimplementsBackoffStrategy {
@OverridepubliclongcomputeDelayBeforeNextRetry(HttpRequestResponsehttpRequestResponse, intretriesAttempted) {
// Exponential backoff: 2^attempt * 1000msreturn (long) Math.pow(2, retriesAttempted) * 1000;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newExponentialBackoff(),
5
);

Request and Response Handlers

Custom Request Handler

importcom.javaquery.http.handler.HttpRequestHandler;
publicclassCustomHeaderHandlerimplementsHttpRequestHandler {
@OverridepublicvoidonRequest(HttpExecutionContextcontext, HttpRequesthttpRequest) {
// Add custom headers before each requesthttpRequest.addHeader("X-Request-ID", UUID.randomUUID().toString());
httpRequest.addHeader("X-Timestamp", String.valueOf(System.currentTimeMillis()));
}
}
// Use the handlerHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newCustomHeaderHandler());
httpClient.execute(context, httpRequest, responseHandler);

Response Handler

importcom.javaquery.http.handler.HttpResponseHandler;
HttpResponseHandler<User> userHandler = newHttpResponseHandler<User>() {
@OverridepublicUseronResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() == 200) {
JSONObjectjson = httpResponse.getJSONObjectBody();
returnparseUser(json);
} elseif (httpResponse.getStatusCode() == 404) {
thrownewUserNotFoundException("User not found");
} else {
thrownewHttpException("Unexpected status: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Failed after maximum retry attempts. Status: {}", httpResponse.getStatusCode());
}
privateUserparseUser(JSONObjectjson) {
// Parse JSON to User objectreturnUser.builder()
.id(json.getLong("id"))
.name(json.getString("name"))
.email(json.getString("email"))
.build();
}
};

Execution Context

The HttpExecutionContext allows you to pass metadata and configure handlers for request execution.

Using Metadata

HttpExecutionContextcontext = newHttpExecutionContext();
// Add metadataMap<String, Object> metadata = newHashMap<>();
metadata.put("userId", "12345");
metadata.put("requestSource", "mobile-app");
context.setMetaData(metadata);
// Add individual metadatacontext.addMetaData("correlationId", UUID.randomUUID().toString());
httpClient.execute(context, httpRequest, responseHandler);

Multiple Request Handlers

HttpExecutionContextcontext = newHttpExecutionContext();
// Add multiple handlerscontext.addHttpRequestHandler(newAuthHeaderHandler());
context.addHttpRequestHandler(newLoggingHandler());
context.addHttpRequestHandler(newMetricsHandler());
// Or set all at onceList<HttpRequestHandler> handlers = Arrays.asList(
newAuthHeaderHandler(),
newLoggingHandler(),
newMetricsHandler()
);
context.setHttpRequestHandlers(handlers);
httpClient.execute(context, httpRequest, responseHandler);

Response Processing

Working with HTTP Response

HttpResponseHandler<Object> handler = newHttpResponseHandler<Object>() {
@OverridepublicObjectonResponse(HttpResponsehttpResponse) {
// Get status codeintstatusCode = httpResponse.getStatusCode();
// Get headersMap<String, String> headers = httpResponse.getHeaders();
StringcontentType = headers.get("Content-Type");
// Get response body as stringStringbody = httpResponse.getBody();
// Parse as JSON ObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
// Parse as JSON ArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
returnbody;
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
};

JSON Response Parsing

// Parse as JSONObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
Stringname = jsonObject.getString("name");
intage = jsonObject.getInt("age");
// Parse as JSONArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
for (inti = 0; i < jsonArray.length(); i++) {
JSONObjectitem = jsonArray.getJSONObject(i);
// Process each item
}

Advanced Usage

Complete Example with All Features

importcom.javaquery.http.*;
importcom.javaquery.http.handler.*;
importcom.javaquery.http.retry.*;
publicclassAdvancedHttpClientExample {
publicstaticvoidmain(String[] args) {
// Build request with all optionsMap<String, String> headers = newHashMap<>();
headers.put("Authorization", "Bearer token123");
headers.put("Accept", "application/json");
Map<String, String> queryParams = newHashMap<>();
queryParams.put("page", "1");
queryParams.put("size", "20");
Stringpayload = "{\"action\":\"update\",\"data\":{\"status\":\"active\"}}";
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newDefaultBackoffStrategy(),
3
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("ComplexRequest", HttpMethod.POST)
.withHost("https://api.example.com")
.withPort(443)
.withEndPoint("/api/v1/resources")
.withHeaders(headers)
.withQueryParameter(queryParams)
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
payload
))
.withRetryPolicy(retryPolicy)
.build();
// Setup execution contextHttpExecutionContextcontext = newHttpExecutionContext();
Map<String, Object> metadata = newHashMap<>();
metadata.put("correlationId", UUID.randomUUID().toString());
metadata.put("requestSource", "backend-service");
context.setMetaData(metadata);
context.addHttpRequestHandler(newHttpRequestHandler() {
@OverridepublicvoidonRequest(HttpExecutionContextctx, HttpRequestreq) {
// Add request timestampreq.addHeader("X-Request-Timestamp", String.valueOf(System.currentTimeMillis()));
}
});
// Execute requestHttpClienthttpClient = newHttpClient();
Resultresult = httpClient.execute(context, request, newHttpResponseHandler<Result>() {
@OverridepublicResultonResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() >= 200 && httpResponse.getStatusCode() < 300) {
returnparseResult(httpResponse.getJSONObjectBody());
} else {
thrownewHttpException("Request failed: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Max retries reached. Status: {}", httpResponse.getStatusCode());
// Send alert, log to monitoring system, etc.
}
}
);
}
privatestaticResultparseResult(JSONObjectjson) {
// Parse JSON to Result objectreturnnewResult(json);
}
}

Handling Different Content Types

// JSON payloadHttpRequest.HttpPayloadjsonPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
"{\"key\":\"value\"}"
);
// Form dataMap<String, Object> formData = newHashMap<>();
formData.put("username", "john");
formData.put("password", "secret");
HttpRequest.HttpPayloadformPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
);
// Multipart form dataMap<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document");
HttpRequest.HttpPayloadmultipartPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
);
// Plain textHttpRequest.HttpPayloadtextPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"text/plain",
"Plain text content"
);
// XMLHttpRequest.HttpPayloadxmlPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/xml",
"<root><item>value</item></root>"
);

Error Handling

try {
httpClient.execute(context, request, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
intstatusCode = httpResponse.getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
returnhttpResponse.getBody();
} elseif (statusCode == 401) {
thrownewAuthenticationException("Authentication required");
} elseif (statusCode == 403) {
thrownewAuthorizationException("Access denied");
} elseif (statusCode == 404) {
thrownewResourceNotFoundException("Resource not found");
} elseif (statusCode >= 500) {
thrownewServerException("Server error: " + statusCode);
} else {
thrownewHttpException("HTTP error: " + statusCode);
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Log or alert when max retries exhaustedthrownewMaxRetriesExceededException(
"Failed after " + retryPolicy.getMaxErrorRetry() + " attempts"
);
}
});
} catch (AuthenticationExceptione) {
// Handle authentication error
} catch (ResourceNotFoundExceptione) {
// Handle not found
} catch (HttpExceptione) {
// Handle general HTTP errors
} catch (Exceptione) {
// Handle unexpected errors
}

Logging

The HTTP client uses SLF4J for logging and integrates with Logstash for structured logging. Request and response details are automatically logged with correlation information.

Enable Logging

Add to your logback.xml:

<configuration>
<appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender">
<encoderclass="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<loggername="com.javaquery.http"level="INFO" />
<rootlevel="INFO">
<appender-refref="CONSOLE" />
</root>
</configuration>

Logged information includes:

  • Request name and method
  • URL and endpoint
  • Headers and query parameters
  • Payload information
  • Response status code
  • Response time
  • Retry attempts
  • Metadata from execution context

API Reference

HttpRequest.HttpRequestBuilder

Builder for creating HTTP requests.

Methods:

  • withHost(String host) - Set the host URL
  • withPort(int port) - Set the port number
  • withEndPoint(String endPoint) - Set the endpoint path
  • withHeader(String key, String value) - Add a single header
  • withHeaders(Map<String, String> headers) - Add multiple headers
  • withQueryParameter(String key, String value) - Add a query parameter
  • withQueryParameter(Map<String, String> params) - Add multiple query parameters
  • withBasicAuth(String username, String password) - Set basic authentication
  • withHttpPayload(HttpPayload payload) - Set the request payload
  • withRetryPolicy(RetryPolicy policy) - Set retry policy
  • build() - Build the HttpRequest

HttpResponse

Response object containing status, headers, and body.

Methods:

  • int getStatusCode() - Get HTTP status code
  • Map<String, String> getHeaders() - Get response headers
  • String getBody() - Get response body as string
  • JSONObject getJSONObjectBody() - Parse body as JSON object
  • JSONArray getJSONArrayBody() - Parse body as JSON array

HttpClient

Main client for executing requests.

Methods:

  • <R> R execute(HttpExecutionContext context, HttpRequest request, HttpResponseHandler<R> handler) - Execute HTTP request

HttpExecutionContext

Context for request execution with metadata and handlers.

Methods:

  • void setMetaData(Map<String, Object> metaData) - Set metadata map
  • void addMetaData(String key, Object value) - Add single metadata entry
  • void addHttpRequestHandler(HttpRequestHandler handler) - Add request handler
  • void setHttpRequestHandlers(List<HttpRequestHandler> handlers) - Set multiple handlers

Requirements

  • Java 11 or higher
  • Apache HttpComponents 4.5.14
  • SLF4J 2.0.16
  • JSON 20250107
  • ScribeJava 8.3.3 (for OAuth)

Dependencies

This module depends on:

  • com.javaquery:util - Utility classes

License

This project is part of the JLite library suite.

Contributing

Contributions are welcome! Please ensure all tests pass before submitting pull requests.

Author

javaquery

Version

Current version: 1.0.7


For more information and updates, visit the JLite GitHub repository.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..

README.md

HTTP Client

A powerful and flexible HTTP client library for Java projects, built on top of Apache HttpComponents. This library provides a clean, fluent API for making HTTP requests with support for retries, OAuth authentication, custom handlers, and comprehensive logging.

Features

  • 🌐 Full HTTP Support - GET, POST, PUT, DELETE, and PATCH methods
  • 🔄 Retry Mechanism - Configurable retry policies with backoff strategies
  • 🔐 Authentication - Built-in support for Basic Auth and OAuth 1.0
  • 📝 Multiple Payload Types - JSON, Form data, Multipart, and String entities
  • 🎯 Request/Response Handlers - Extensible hooks for request and response processing
  • 📊 Structured Logging - Logstash integration for detailed request/response logging
  • ⚙️ Flexible Configuration - Custom headers, query parameters, and execution context
  • 🛠️ Error Handling - Comprehensive exception handling and retry mechanisms

Installation

Gradle

dependencies {
implementation 'com.javaquery:httpclient:1.0.7'
}

Maven

<dependency>
<groupId>com.javaquery</groupId>
<artifactId>httpclient</artifactId>
<version>1.0.7</version>
</dependency>

Quick Start

Simple GET Request

importcom.javaquery.http.*;
importcom.javaquery.http.handler.HttpResponseHandler;
// Build the requestHttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("GetUsers", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.build();
// Create execution contextHttpExecutionContextcontext = newHttpExecutionContext();
// Execute requestHttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
});

POST Request with JSON Payload

StringjsonPayload = "{\"name\":\"John Doe\",\"email\":\"john@example.com\"}";
HttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("CreateUser", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withHeader("Content-Type", "application/json")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8, "application/json", jsonPayload
))
.build();
HttpExecutionContextcontext = newHttpExecutionContext();
HttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<JSONObject>() {
@OverridepublicJSONObjectonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getJSONObjectBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
System.err.println("Max retries reached");
}
});

HTTP Methods

GET Request

HttpRequestgetRequest = newHttpRequest.HttpRequestBuilder("GetRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withQueryParameter("page", "1")
.withQueryParameter("size", "20")
.build();

POST Request with Form Data

Map<String, Object> formData = newHashMap<>();
formData.put("username", "john.doe");
formData.put("email", "john@example.com");
HttpRequestpostRequest = newHttpRequest.HttpRequestBuilder("PostForm", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/submit")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
))
.build();

POST Request with Multipart File Upload

Map<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document upload");
HttpRequestuploadRequest = newHttpRequest.HttpRequestBuilder("FileUpload", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/upload")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
))
.build();

PUT Request

StringupdatePayload = "{\"status\":\"active\"}";
HttpRequestputRequest = newHttpRequest.HttpRequestBuilder("UpdateUser", HttpMethod.PUT)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
updatePayload
))
.build();

DELETE Request

HttpRequestdeleteRequest = newHttpRequest.HttpRequestBuilder("DeleteUser", HttpMethod.DELETE)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.build();

Authentication

Basic Authentication

HttpRequestauthRequest = newHttpRequest.HttpRequestBuilder("SecureEndpoint", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/secure")
.withBasicAuth("username", "password")
.build();

OAuth 1.0

importcom.javaquery.http.oauth.OAuthConfig;
OAuthConfigoauthConfig = OAuthConfig.builder()
.consumerKey("your-consumer-key")
.consumerSecret("your-consumer-secret")
.accessToken("your-access-token")
.accessTokenSecret("your-access-token-secret")
.build();
HttpRequestoauthRequest = newHttpRequest.HttpRequestBuilder("OAuthRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/oauth/resource")
.build();
// Add OAuth handler to execution contextHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newOAuth10HttpRequestHandler(oauthConfig));
httpClient.execute(context, oauthRequest, responseHandler);

Headers and Query Parameters

Adding Headers

// Single headerHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeader("Authorization", "Bearer token123")
.withHeader("X-Custom-Header", "value")
.build();
// Multiple headersMap<String, String> headers = newHashMap<>();
headers.put("Content-Type", "application/json");
headers.put("Accept", "application/json");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeaders(headers)
.build();

Adding Query Parameters

// Single parameterHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/search")
.withQueryParameter("q", "java")
.withQueryParameter("limit", "10")
.build();
// Multiple parametersMap<String, String> params = newHashMap<>();
params.put("page", "1");
params.put("size", "20");
params.put("sort", "name");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withQueryParameter(params)
.build();

Retry Policies

Default Retry Policy

importcom.javaquery.http.DefaultRetryPolicy;
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("RetryRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/unstable")
.withRetryPolicy(DefaultRetryPolicy.get(3)) // Retry up to 3 times
.build();

Custom Retry Policy

importcom.javaquery.http.retry.*;
RetryPolicycustomRetry = newRetryPolicy(
newDefaultRetryCondition(), // When to retrynewDefaultBackoffStrategy(), // How long to wait between retries5// Max retry attempts
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("CustomRetry", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withRetryPolicy(customRetry)
.build();

Implementing Custom Retry Condition

importcom.javaquery.http.retry.RetryCondition;
publicclassCustomRetryConditionimplementsRetryCondition {
@OverridepublicbooleanshouldRetry(HttpRequestResponsehttpRequestResponse) {
HttpResponseresponse = httpRequestResponse.getHttpResponse();
// Retry on 5xx errors or specific 4xx errorsintstatusCode = response.getStatusCode();
returnstatusCode >= 500 || statusCode == 429 || statusCode == 408;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newCustomRetryCondition(),
newDefaultBackoffStrategy(),
3
);

Implementing Custom Backoff Strategy

importcom.javaquery.http.retry.BackoffStrategy;
publicclassExponentialBackoffimplementsBackoffStrategy {
@OverridepubliclongcomputeDelayBeforeNextRetry(HttpRequestResponsehttpRequestResponse, intretriesAttempted) {
// Exponential backoff: 2^attempt * 1000msreturn (long) Math.pow(2, retriesAttempted) * 1000;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newExponentialBackoff(),
5
);

Request and Response Handlers

Custom Request Handler

importcom.javaquery.http.handler.HttpRequestHandler;
publicclassCustomHeaderHandlerimplementsHttpRequestHandler {
@OverridepublicvoidonRequest(HttpExecutionContextcontext, HttpRequesthttpRequest) {
// Add custom headers before each requesthttpRequest.addHeader("X-Request-ID", UUID.randomUUID().toString());
httpRequest.addHeader("X-Timestamp", String.valueOf(System.currentTimeMillis()));
}
}
// Use the handlerHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newCustomHeaderHandler());
httpClient.execute(context, httpRequest, responseHandler);

Response Handler

importcom.javaquery.http.handler.HttpResponseHandler;
HttpResponseHandler<User> userHandler = newHttpResponseHandler<User>() {
@OverridepublicUseronResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() == 200) {
JSONObjectjson = httpResponse.getJSONObjectBody();
returnparseUser(json);
} elseif (httpResponse.getStatusCode() == 404) {
thrownewUserNotFoundException("User not found");
} else {
thrownewHttpException("Unexpected status: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Failed after maximum retry attempts. Status: {}", httpResponse.getStatusCode());
}
privateUserparseUser(JSONObjectjson) {
// Parse JSON to User objectreturnUser.builder()
.id(json.getLong("id"))
.name(json.getString("name"))
.email(json.getString("email"))
.build();
}
};

Execution Context

The HttpExecutionContext allows you to pass metadata and configure handlers for request execution.

Using Metadata

HttpExecutionContextcontext = newHttpExecutionContext();
// Add metadataMap<String, Object> metadata = newHashMap<>();
metadata.put("userId", "12345");
metadata.put("requestSource", "mobile-app");
context.setMetaData(metadata);
// Add individual metadatacontext.addMetaData("correlationId", UUID.randomUUID().toString());
httpClient.execute(context, httpRequest, responseHandler);

Multiple Request Handlers

HttpExecutionContextcontext = newHttpExecutionContext();
// Add multiple handlerscontext.addHttpRequestHandler(newAuthHeaderHandler());
context.addHttpRequestHandler(newLoggingHandler());
context.addHttpRequestHandler(newMetricsHandler());
// Or set all at onceList<HttpRequestHandler> handlers = Arrays.asList(
newAuthHeaderHandler(),
newLoggingHandler(),
newMetricsHandler()
);
context.setHttpRequestHandlers(handlers);
httpClient.execute(context, httpRequest, responseHandler);

Response Processing

Working with HTTP Response

HttpResponseHandler<Object> handler = newHttpResponseHandler<Object>() {
@OverridepublicObjectonResponse(HttpResponsehttpResponse) {
// Get status codeintstatusCode = httpResponse.getStatusCode();
// Get headersMap<String, String> headers = httpResponse.getHeaders();
StringcontentType = headers.get("Content-Type");
// Get response body as stringStringbody = httpResponse.getBody();
// Parse as JSON ObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
// Parse as JSON ArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
returnbody;
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
};

JSON Response Parsing

// Parse as JSONObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
Stringname = jsonObject.getString("name");
intage = jsonObject.getInt("age");
// Parse as JSONArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
for (inti = 0; i < jsonArray.length(); i++) {
JSONObjectitem = jsonArray.getJSONObject(i);
// Process each item
}

Advanced Usage

Complete Example with All Features

importcom.javaquery.http.*;
importcom.javaquery.http.handler.*;
importcom.javaquery.http.retry.*;
publicclassAdvancedHttpClientExample {
publicstaticvoidmain(String[] args) {
// Build request with all optionsMap<String, String> headers = newHashMap<>();
headers.put("Authorization", "Bearer token123");
headers.put("Accept", "application/json");
Map<String, String> queryParams = newHashMap<>();
queryParams.put("page", "1");
queryParams.put("size", "20");
Stringpayload = "{\"action\":\"update\",\"data\":{\"status\":\"active\"}}";
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newDefaultBackoffStrategy(),
3
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("ComplexRequest", HttpMethod.POST)
.withHost("https://api.example.com")
.withPort(443)
.withEndPoint("/api/v1/resources")
.withHeaders(headers)
.withQueryParameter(queryParams)
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
payload
))
.withRetryPolicy(retryPolicy)
.build();
// Setup execution contextHttpExecutionContextcontext = newHttpExecutionContext();
Map<String, Object> metadata = newHashMap<>();
metadata.put("correlationId", UUID.randomUUID().toString());
metadata.put("requestSource", "backend-service");
context.setMetaData(metadata);
context.addHttpRequestHandler(newHttpRequestHandler() {
@OverridepublicvoidonRequest(HttpExecutionContextctx, HttpRequestreq) {
// Add request timestampreq.addHeader("X-Request-Timestamp", String.valueOf(System.currentTimeMillis()));
}
});
// Execute requestHttpClienthttpClient = newHttpClient();
Resultresult = httpClient.execute(context, request, newHttpResponseHandler<Result>() {
@OverridepublicResultonResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() >= 200 && httpResponse.getStatusCode() < 300) {
returnparseResult(httpResponse.getJSONObjectBody());
} else {
thrownewHttpException("Request failed: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Max retries reached. Status: {}", httpResponse.getStatusCode());
// Send alert, log to monitoring system, etc.
}
}
);
}
privatestaticResultparseResult(JSONObjectjson) {
// Parse JSON to Result objectreturnnewResult(json);
}
}

Handling Different Content Types

// JSON payloadHttpRequest.HttpPayloadjsonPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
"{\"key\":\"value\"}"
);
// Form dataMap<String, Object> formData = newHashMap<>();
formData.put("username", "john");
formData.put("password", "secret");
HttpRequest.HttpPayloadformPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
);
// Multipart form dataMap<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document");
HttpRequest.HttpPayloadmultipartPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
);
// Plain textHttpRequest.HttpPayloadtextPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"text/plain",
"Plain text content"
);
// XMLHttpRequest.HttpPayloadxmlPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/xml",
"<root><item>value</item></root>"
);

Error Handling

try {
httpClient.execute(context, request, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
intstatusCode = httpResponse.getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
returnhttpResponse.getBody();
} elseif (statusCode == 401) {
thrownewAuthenticationException("Authentication required");
} elseif (statusCode == 403) {
thrownewAuthorizationException("Access denied");
} elseif (statusCode == 404) {
thrownewResourceNotFoundException("Resource not found");
} elseif (statusCode >= 500) {
thrownewServerException("Server error: " + statusCode);
} else {
thrownewHttpException("HTTP error: " + statusCode);
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Log or alert when max retries exhaustedthrownewMaxRetriesExceededException(
"Failed after " + retryPolicy.getMaxErrorRetry() + " attempts"
);
}
});
} catch (AuthenticationExceptione) {
// Handle authentication error
} catch (ResourceNotFoundExceptione) {
// Handle not found
} catch (HttpExceptione) {
// Handle general HTTP errors
} catch (Exceptione) {
// Handle unexpected errors
}

Logging

The HTTP client uses SLF4J for logging and integrates with Logstash for structured logging. Request and response details are automatically logged with correlation information.

Enable Logging

Add to your logback.xml:

<configuration>
<appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender">
<encoderclass="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<loggername="com.javaquery.http"level="INFO" />
<rootlevel="INFO">
<appender-refref="CONSOLE" />
</root>
</configuration>

Logged information includes:

  • Request name and method
  • URL and endpoint
  • Headers and query parameters
  • Payload information
  • Response status code
  • Response time
  • Retry attempts
  • Metadata from execution context

API Reference

HttpRequest.HttpRequestBuilder

Builder for creating HTTP requests.

Methods:

  • withHost(String host) - Set the host URL
  • withPort(int port) - Set the port number
  • withEndPoint(String endPoint) - Set the endpoint path
  • withHeader(String key, String value) - Add a single header
  • withHeaders(Map<String, String> headers) - Add multiple headers
  • withQueryParameter(String key, String value) - Add a query parameter
  • withQueryParameter(Map<String, String> params) - Add multiple query parameters
  • withBasicAuth(String username, String password) - Set basic authentication
  • withHttpPayload(HttpPayload payload) - Set the request payload
  • withRetryPolicy(RetryPolicy policy) - Set retry policy
  • build() - Build the HttpRequest

HttpResponse

Response object containing status, headers, and body.

Methods:

  • int getStatusCode() - Get HTTP status code
  • Map<String, String> getHeaders() - Get response headers
  • String getBody() - Get response body as string
  • JSONObject getJSONObjectBody() - Parse body as JSON object
  • JSONArray getJSONArrayBody() - Parse body as JSON array

HttpClient

Main client for executing requests.

Methods:

  • <R> R execute(HttpExecutionContext context, HttpRequest request, HttpResponseHandler<R> handler) - Execute HTTP request

HttpExecutionContext

Context for request execution with metadata and handlers.

Methods:

  • void setMetaData(Map<String, Object> metaData) - Set metadata map
  • void addMetaData(String key, Object value) - Add single metadata entry
  • void addHttpRequestHandler(HttpRequestHandler handler) - Add request handler
  • void setHttpRequestHandlers(List<HttpRequestHandler> handlers) - Set multiple handlers

Requirements

  • Java 11 or higher
  • Apache HttpComponents 4.5.14
  • SLF4J 2.0.16
  • JSON 20250107
  • ScribeJava 8.3.3 (for OAuth)

Dependencies

This module depends on:

  • com.javaquery:util - Utility classes

License

This project is part of the JLite library suite.

Contributing

Contributions are welcome! Please ensure all tests pass before submitting pull requests.

Author

javaquery

Version

Current version: 1.0.7


For more information and updates, visit the JLite GitHub repository.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..

README.md

HTTP Client

A powerful and flexible HTTP client library for Java projects, built on top of Apache HttpComponents. This library provides a clean, fluent API for making HTTP requests with support for retries, OAuth authentication, custom handlers, and comprehensive logging.

Features

  • 🌐 Full HTTP Support - GET, POST, PUT, DELETE, and PATCH methods
  • 🔄 Retry Mechanism - Configurable retry policies with backoff strategies
  • 🔐 Authentication - Built-in support for Basic Auth and OAuth 1.0
  • 📝 Multiple Payload Types - JSON, Form data, Multipart, and String entities
  • 🎯 Request/Response Handlers - Extensible hooks for request and response processing
  • 📊 Structured Logging - Logstash integration for detailed request/response logging
  • ⚙️ Flexible Configuration - Custom headers, query parameters, and execution context
  • 🛠️ Error Handling - Comprehensive exception handling and retry mechanisms

Installation

Gradle

dependencies {
implementation 'com.javaquery:httpclient:1.0.7'
}

Maven

<dependency>
<groupId>com.javaquery</groupId>
<artifactId>httpclient</artifactId>
<version>1.0.7</version>
</dependency>

Quick Start

Simple GET Request

importcom.javaquery.http.*;
importcom.javaquery.http.handler.HttpResponseHandler;
// Build the requestHttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("GetUsers", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.build();
// Create execution contextHttpExecutionContextcontext = newHttpExecutionContext();
// Execute requestHttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
});

POST Request with JSON Payload

StringjsonPayload = "{\"name\":\"John Doe\",\"email\":\"john@example.com\"}";
HttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("CreateUser", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withHeader("Content-Type", "application/json")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8, "application/json", jsonPayload
))
.build();
HttpExecutionContextcontext = newHttpExecutionContext();
HttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<JSONObject>() {
@OverridepublicJSONObjectonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getJSONObjectBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
System.err.println("Max retries reached");
}
});

HTTP Methods

GET Request

HttpRequestgetRequest = newHttpRequest.HttpRequestBuilder("GetRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withQueryParameter("page", "1")
.withQueryParameter("size", "20")
.build();

POST Request with Form Data

Map<String, Object> formData = newHashMap<>();
formData.put("username", "john.doe");
formData.put("email", "john@example.com");
HttpRequestpostRequest = newHttpRequest.HttpRequestBuilder("PostForm", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/submit")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
))
.build();

POST Request with Multipart File Upload

Map<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document upload");
HttpRequestuploadRequest = newHttpRequest.HttpRequestBuilder("FileUpload", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/upload")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
))
.build();

PUT Request

StringupdatePayload = "{\"status\":\"active\"}";
HttpRequestputRequest = newHttpRequest.HttpRequestBuilder("UpdateUser", HttpMethod.PUT)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
updatePayload
))
.build();

DELETE Request

HttpRequestdeleteRequest = newHttpRequest.HttpRequestBuilder("DeleteUser", HttpMethod.DELETE)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.build();

Authentication

Basic Authentication

HttpRequestauthRequest = newHttpRequest.HttpRequestBuilder("SecureEndpoint", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/secure")
.withBasicAuth("username", "password")
.build();

OAuth 1.0

importcom.javaquery.http.oauth.OAuthConfig;
OAuthConfigoauthConfig = OAuthConfig.builder()
.consumerKey("your-consumer-key")
.consumerSecret("your-consumer-secret")
.accessToken("your-access-token")
.accessTokenSecret("your-access-token-secret")
.build();
HttpRequestoauthRequest = newHttpRequest.HttpRequestBuilder("OAuthRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/oauth/resource")
.build();
// Add OAuth handler to execution contextHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newOAuth10HttpRequestHandler(oauthConfig));
httpClient.execute(context, oauthRequest, responseHandler);

Headers and Query Parameters

Adding Headers

// Single headerHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeader("Authorization", "Bearer token123")
.withHeader("X-Custom-Header", "value")
.build();
// Multiple headersMap<String, String> headers = newHashMap<>();
headers.put("Content-Type", "application/json");
headers.put("Accept", "application/json");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeaders(headers)
.build();

Adding Query Parameters

// Single parameterHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/search")
.withQueryParameter("q", "java")
.withQueryParameter("limit", "10")
.build();
// Multiple parametersMap<String, String> params = newHashMap<>();
params.put("page", "1");
params.put("size", "20");
params.put("sort", "name");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withQueryParameter(params)
.build();

Retry Policies

Default Retry Policy

importcom.javaquery.http.DefaultRetryPolicy;
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("RetryRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/unstable")
.withRetryPolicy(DefaultRetryPolicy.get(3)) // Retry up to 3 times
.build();

Custom Retry Policy

importcom.javaquery.http.retry.*;
RetryPolicycustomRetry = newRetryPolicy(
newDefaultRetryCondition(), // When to retrynewDefaultBackoffStrategy(), // How long to wait between retries5// Max retry attempts
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("CustomRetry", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withRetryPolicy(customRetry)
.build();

Implementing Custom Retry Condition

importcom.javaquery.http.retry.RetryCondition;
publicclassCustomRetryConditionimplementsRetryCondition {
@OverridepublicbooleanshouldRetry(HttpRequestResponsehttpRequestResponse) {
HttpResponseresponse = httpRequestResponse.getHttpResponse();
// Retry on 5xx errors or specific 4xx errorsintstatusCode = response.getStatusCode();
returnstatusCode >= 500 || statusCode == 429 || statusCode == 408;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newCustomRetryCondition(),
newDefaultBackoffStrategy(),
3
);

Implementing Custom Backoff Strategy

importcom.javaquery.http.retry.BackoffStrategy;
publicclassExponentialBackoffimplementsBackoffStrategy {
@OverridepubliclongcomputeDelayBeforeNextRetry(HttpRequestResponsehttpRequestResponse, intretriesAttempted) {
// Exponential backoff: 2^attempt * 1000msreturn (long) Math.pow(2, retriesAttempted) * 1000;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newExponentialBackoff(),
5
);

Request and Response Handlers

Custom Request Handler

importcom.javaquery.http.handler.HttpRequestHandler;
publicclassCustomHeaderHandlerimplementsHttpRequestHandler {
@OverridepublicvoidonRequest(HttpExecutionContextcontext, HttpRequesthttpRequest) {
// Add custom headers before each requesthttpRequest.addHeader("X-Request-ID", UUID.randomUUID().toString());
httpRequest.addHeader("X-Timestamp", String.valueOf(System.currentTimeMillis()));
}
}
// Use the handlerHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newCustomHeaderHandler());
httpClient.execute(context, httpRequest, responseHandler);

Response Handler

importcom.javaquery.http.handler.HttpResponseHandler;
HttpResponseHandler<User> userHandler = newHttpResponseHandler<User>() {
@OverridepublicUseronResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() == 200) {
JSONObjectjson = httpResponse.getJSONObjectBody();
returnparseUser(json);
} elseif (httpResponse.getStatusCode() == 404) {
thrownewUserNotFoundException("User not found");
} else {
thrownewHttpException("Unexpected status: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Failed after maximum retry attempts. Status: {}", httpResponse.getStatusCode());
}
privateUserparseUser(JSONObjectjson) {
// Parse JSON to User objectreturnUser.builder()
.id(json.getLong("id"))
.name(json.getString("name"))
.email(json.getString("email"))
.build();
}
};

Execution Context

The HttpExecutionContext allows you to pass metadata and configure handlers for request execution.

Using Metadata

HttpExecutionContextcontext = newHttpExecutionContext();
// Add metadataMap<String, Object> metadata = newHashMap<>();
metadata.put("userId", "12345");
metadata.put("requestSource", "mobile-app");
context.setMetaData(metadata);
// Add individual metadatacontext.addMetaData("correlationId", UUID.randomUUID().toString());
httpClient.execute(context, httpRequest, responseHandler);

Multiple Request Handlers

HttpExecutionContextcontext = newHttpExecutionContext();
// Add multiple handlerscontext.addHttpRequestHandler(newAuthHeaderHandler());
context.addHttpRequestHandler(newLoggingHandler());
context.addHttpRequestHandler(newMetricsHandler());
// Or set all at onceList<HttpRequestHandler> handlers = Arrays.asList(
newAuthHeaderHandler(),
newLoggingHandler(),
newMetricsHandler()
);
context.setHttpRequestHandlers(handlers);
httpClient.execute(context, httpRequest, responseHandler);

Response Processing

Working with HTTP Response

HttpResponseHandler<Object> handler = newHttpResponseHandler<Object>() {
@OverridepublicObjectonResponse(HttpResponsehttpResponse) {
// Get status codeintstatusCode = httpResponse.getStatusCode();
// Get headersMap<String, String> headers = httpResponse.getHeaders();
StringcontentType = headers.get("Content-Type");
// Get response body as stringStringbody = httpResponse.getBody();
// Parse as JSON ObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
// Parse as JSON ArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
returnbody;
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
};

JSON Response Parsing

// Parse as JSONObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
Stringname = jsonObject.getString("name");
intage = jsonObject.getInt("age");
// Parse as JSONArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
for (inti = 0; i < jsonArray.length(); i++) {
JSONObjectitem = jsonArray.getJSONObject(i);
// Process each item
}

Advanced Usage

Complete Example with All Features

importcom.javaquery.http.*;
importcom.javaquery.http.handler.*;
importcom.javaquery.http.retry.*;
publicclassAdvancedHttpClientExample {
publicstaticvoidmain(String[] args) {
// Build request with all optionsMap<String, String> headers = newHashMap<>();
headers.put("Authorization", "Bearer token123");
headers.put("Accept", "application/json");
Map<String, String> queryParams = newHashMap<>();
queryParams.put("page", "1");
queryParams.put("size", "20");
Stringpayload = "{\"action\":\"update\",\"data\":{\"status\":\"active\"}}";
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newDefaultBackoffStrategy(),
3
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("ComplexRequest", HttpMethod.POST)
.withHost("https://api.example.com")
.withPort(443)
.withEndPoint("/api/v1/resources")
.withHeaders(headers)
.withQueryParameter(queryParams)
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
payload
))
.withRetryPolicy(retryPolicy)
.build();
// Setup execution contextHttpExecutionContextcontext = newHttpExecutionContext();
Map<String, Object> metadata = newHashMap<>();
metadata.put("correlationId", UUID.randomUUID().toString());
metadata.put("requestSource", "backend-service");
context.setMetaData(metadata);
context.addHttpRequestHandler(newHttpRequestHandler() {
@OverridepublicvoidonRequest(HttpExecutionContextctx, HttpRequestreq) {
// Add request timestampreq.addHeader("X-Request-Timestamp", String.valueOf(System.currentTimeMillis()));
}
});
// Execute requestHttpClienthttpClient = newHttpClient();
Resultresult = httpClient.execute(context, request, newHttpResponseHandler<Result>() {
@OverridepublicResultonResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() >= 200 && httpResponse.getStatusCode() < 300) {
returnparseResult(httpResponse.getJSONObjectBody());
} else {
thrownewHttpException("Request failed: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Max retries reached. Status: {}", httpResponse.getStatusCode());
// Send alert, log to monitoring system, etc.
}
}
);
}
privatestaticResultparseResult(JSONObjectjson) {
// Parse JSON to Result objectreturnnewResult(json);
}
}

Handling Different Content Types

// JSON payloadHttpRequest.HttpPayloadjsonPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
"{\"key\":\"value\"}"
);
// Form dataMap<String, Object> formData = newHashMap<>();
formData.put("username", "john");
formData.put("password", "secret");
HttpRequest.HttpPayloadformPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
);
// Multipart form dataMap<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document");
HttpRequest.HttpPayloadmultipartPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
);
// Plain textHttpRequest.HttpPayloadtextPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"text/plain",
"Plain text content"
);
// XMLHttpRequest.HttpPayloadxmlPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/xml",
"<root><item>value</item></root>"
);

Error Handling

try {
httpClient.execute(context, request, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
intstatusCode = httpResponse.getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
returnhttpResponse.getBody();
} elseif (statusCode == 401) {
thrownewAuthenticationException("Authentication required");
} elseif (statusCode == 403) {
thrownewAuthorizationException("Access denied");
} elseif (statusCode == 404) {
thrownewResourceNotFoundException("Resource not found");
} elseif (statusCode >= 500) {
thrownewServerException("Server error: " + statusCode);
} else {
thrownewHttpException("HTTP error: " + statusCode);
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Log or alert when max retries exhaustedthrownewMaxRetriesExceededException(
"Failed after " + retryPolicy.getMaxErrorRetry() + " attempts"
);
}
});
} catch (AuthenticationExceptione) {
// Handle authentication error
} catch (ResourceNotFoundExceptione) {
// Handle not found
} catch (HttpExceptione) {
// Handle general HTTP errors
} catch (Exceptione) {
// Handle unexpected errors
}

Logging

The HTTP client uses SLF4J for logging and integrates with Logstash for structured logging. Request and response details are automatically logged with correlation information.

Enable Logging

Add to your logback.xml:

<configuration>
<appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender">
<encoderclass="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<loggername="com.javaquery.http"level="INFO" />
<rootlevel="INFO">
<appender-refref="CONSOLE" />
</root>
</configuration>

Logged information includes:

  • Request name and method
  • URL and endpoint
  • Headers and query parameters
  • Payload information
  • Response status code
  • Response time
  • Retry attempts
  • Metadata from execution context

API Reference

HttpRequest.HttpRequestBuilder

Builder for creating HTTP requests.

Methods:

  • withHost(String host) - Set the host URL
  • withPort(int port) - Set the port number
  • withEndPoint(String endPoint) - Set the endpoint path
  • withHeader(String key, String value) - Add a single header
  • withHeaders(Map<String, String> headers) - Add multiple headers
  • withQueryParameter(String key, String value) - Add a query parameter
  • withQueryParameter(Map<String, String> params) - Add multiple query parameters
  • withBasicAuth(String username, String password) - Set basic authentication
  • withHttpPayload(HttpPayload payload) - Set the request payload
  • withRetryPolicy(RetryPolicy policy) - Set retry policy
  • build() - Build the HttpRequest

HttpResponse

Response object containing status, headers, and body.

Methods:

  • int getStatusCode() - Get HTTP status code
  • Map<String, String> getHeaders() - Get response headers
  • String getBody() - Get response body as string
  • JSONObject getJSONObjectBody() - Parse body as JSON object
  • JSONArray getJSONArrayBody() - Parse body as JSON array

HttpClient

Main client for executing requests.

Methods:

  • <R> R execute(HttpExecutionContext context, HttpRequest request, HttpResponseHandler<R> handler) - Execute HTTP request

HttpExecutionContext

Context for request execution with metadata and handlers.

Methods:

  • void setMetaData(Map<String, Object> metaData) - Set metadata map
  • void addMetaData(String key, Object value) - Add single metadata entry
  • void addHttpRequestHandler(HttpRequestHandler handler) - Add request handler
  • void setHttpRequestHandlers(List<HttpRequestHandler> handlers) - Set multiple handlers

Requirements

  • Java 11 or higher
  • Apache HttpComponents 4.5.14
  • SLF4J 2.0.16
  • JSON 20250107
  • ScribeJava 8.3.3 (for OAuth)

Dependencies

This module depends on:

  • com.javaquery:util - Utility classes

License

This project is part of the JLite library suite.

Contributing

Contributions are welcome! Please ensure all tests pass before submitting pull requests.

Author

javaquery

Version

Current version: 1.0.7


For more information and updates, visit the JLite GitHub repository.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..

README.md

HTTP Client

A powerful and flexible HTTP client library for Java projects, built on top of Apache HttpComponents. This library provides a clean, fluent API for making HTTP requests with support for retries, OAuth authentication, custom handlers, and comprehensive logging.

Features

  • 🌐 Full HTTP Support - GET, POST, PUT, DELETE, and PATCH methods
  • 🔄 Retry Mechanism - Configurable retry policies with backoff strategies
  • 🔐 Authentication - Built-in support for Basic Auth and OAuth 1.0
  • 📝 Multiple Payload Types - JSON, Form data, Multipart, and String entities
  • 🎯 Request/Response Handlers - Extensible hooks for request and response processing
  • 📊 Structured Logging - Logstash integration for detailed request/response logging
  • ⚙️ Flexible Configuration - Custom headers, query parameters, and execution context
  • 🛠️ Error Handling - Comprehensive exception handling and retry mechanisms

Installation

Gradle

dependencies {
implementation 'com.javaquery:httpclient:1.0.7'
}

Maven

<dependency>
<groupId>com.javaquery</groupId>
<artifactId>httpclient</artifactId>
<version>1.0.7</version>
</dependency>

Quick Start

Simple GET Request

importcom.javaquery.http.*;
importcom.javaquery.http.handler.HttpResponseHandler;
// Build the requestHttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("GetUsers", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.build();
// Create execution contextHttpExecutionContextcontext = newHttpExecutionContext();
// Execute requestHttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
});

POST Request with JSON Payload

StringjsonPayload = "{\"name\":\"John Doe\",\"email\":\"john@example.com\"}";
HttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("CreateUser", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withHeader("Content-Type", "application/json")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8, "application/json", jsonPayload
))
.build();
HttpExecutionContextcontext = newHttpExecutionContext();
HttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<JSONObject>() {
@OverridepublicJSONObjectonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getJSONObjectBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
System.err.println("Max retries reached");
}
});

HTTP Methods

GET Request

HttpRequestgetRequest = newHttpRequest.HttpRequestBuilder("GetRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withQueryParameter("page", "1")
.withQueryParameter("size", "20")
.build();

POST Request with Form Data

Map<String, Object> formData = newHashMap<>();
formData.put("username", "john.doe");
formData.put("email", "john@example.com");
HttpRequestpostRequest = newHttpRequest.HttpRequestBuilder("PostForm", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/submit")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
))
.build();

POST Request with Multipart File Upload

Map<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document upload");
HttpRequestuploadRequest = newHttpRequest.HttpRequestBuilder("FileUpload", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/upload")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
))
.build();

PUT Request

StringupdatePayload = "{\"status\":\"active\"}";
HttpRequestputRequest = newHttpRequest.HttpRequestBuilder("UpdateUser", HttpMethod.PUT)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
updatePayload
))
.build();

DELETE Request

HttpRequestdeleteRequest = newHttpRequest.HttpRequestBuilder("DeleteUser", HttpMethod.DELETE)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.build();

Authentication

Basic Authentication

HttpRequestauthRequest = newHttpRequest.HttpRequestBuilder("SecureEndpoint", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/secure")
.withBasicAuth("username", "password")
.build();

OAuth 1.0

importcom.javaquery.http.oauth.OAuthConfig;
OAuthConfigoauthConfig = OAuthConfig.builder()
.consumerKey("your-consumer-key")
.consumerSecret("your-consumer-secret")
.accessToken("your-access-token")
.accessTokenSecret("your-access-token-secret")
.build();
HttpRequestoauthRequest = newHttpRequest.HttpRequestBuilder("OAuthRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/oauth/resource")
.build();
// Add OAuth handler to execution contextHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newOAuth10HttpRequestHandler(oauthConfig));
httpClient.execute(context, oauthRequest, responseHandler);

Headers and Query Parameters

Adding Headers

// Single headerHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeader("Authorization", "Bearer token123")
.withHeader("X-Custom-Header", "value")
.build();
// Multiple headersMap<String, String> headers = newHashMap<>();
headers.put("Content-Type", "application/json");
headers.put("Accept", "application/json");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeaders(headers)
.build();

Adding Query Parameters

// Single parameterHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/search")
.withQueryParameter("q", "java")
.withQueryParameter("limit", "10")
.build();
// Multiple parametersMap<String, String> params = newHashMap<>();
params.put("page", "1");
params.put("size", "20");
params.put("sort", "name");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withQueryParameter(params)
.build();

Retry Policies

Default Retry Policy

importcom.javaquery.http.DefaultRetryPolicy;
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("RetryRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/unstable")
.withRetryPolicy(DefaultRetryPolicy.get(3)) // Retry up to 3 times
.build();

Custom Retry Policy

importcom.javaquery.http.retry.*;
RetryPolicycustomRetry = newRetryPolicy(
newDefaultRetryCondition(), // When to retrynewDefaultBackoffStrategy(), // How long to wait between retries5// Max retry attempts
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("CustomRetry", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withRetryPolicy(customRetry)
.build();

Implementing Custom Retry Condition

importcom.javaquery.http.retry.RetryCondition;
publicclassCustomRetryConditionimplementsRetryCondition {
@OverridepublicbooleanshouldRetry(HttpRequestResponsehttpRequestResponse) {
HttpResponseresponse = httpRequestResponse.getHttpResponse();
// Retry on 5xx errors or specific 4xx errorsintstatusCode = response.getStatusCode();
returnstatusCode >= 500 || statusCode == 429 || statusCode == 408;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newCustomRetryCondition(),
newDefaultBackoffStrategy(),
3
);

Implementing Custom Backoff Strategy

importcom.javaquery.http.retry.BackoffStrategy;
publicclassExponentialBackoffimplementsBackoffStrategy {
@OverridepubliclongcomputeDelayBeforeNextRetry(HttpRequestResponsehttpRequestResponse, intretriesAttempted) {
// Exponential backoff: 2^attempt * 1000msreturn (long) Math.pow(2, retriesAttempted) * 1000;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newExponentialBackoff(),
5
);

Request and Response Handlers

Custom Request Handler

importcom.javaquery.http.handler.HttpRequestHandler;
publicclassCustomHeaderHandlerimplementsHttpRequestHandler {
@OverridepublicvoidonRequest(HttpExecutionContextcontext, HttpRequesthttpRequest) {
// Add custom headers before each requesthttpRequest.addHeader("X-Request-ID", UUID.randomUUID().toString());
httpRequest.addHeader("X-Timestamp", String.valueOf(System.currentTimeMillis()));
}
}
// Use the handlerHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newCustomHeaderHandler());
httpClient.execute(context, httpRequest, responseHandler);

Response Handler

importcom.javaquery.http.handler.HttpResponseHandler;
HttpResponseHandler<User> userHandler = newHttpResponseHandler<User>() {
@OverridepublicUseronResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() == 200) {
JSONObjectjson = httpResponse.getJSONObjectBody();
returnparseUser(json);
} elseif (httpResponse.getStatusCode() == 404) {
thrownewUserNotFoundException("User not found");
} else {
thrownewHttpException("Unexpected status: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Failed after maximum retry attempts. Status: {}", httpResponse.getStatusCode());
}
privateUserparseUser(JSONObjectjson) {
// Parse JSON to User objectreturnUser.builder()
.id(json.getLong("id"))
.name(json.getString("name"))
.email(json.getString("email"))
.build();
}
};

Execution Context

The HttpExecutionContext allows you to pass metadata and configure handlers for request execution.

Using Metadata

HttpExecutionContextcontext = newHttpExecutionContext();
// Add metadataMap<String, Object> metadata = newHashMap<>();
metadata.put("userId", "12345");
metadata.put("requestSource", "mobile-app");
context.setMetaData(metadata);
// Add individual metadatacontext.addMetaData("correlationId", UUID.randomUUID().toString());
httpClient.execute(context, httpRequest, responseHandler);

Multiple Request Handlers

HttpExecutionContextcontext = newHttpExecutionContext();
// Add multiple handlerscontext.addHttpRequestHandler(newAuthHeaderHandler());
context.addHttpRequestHandler(newLoggingHandler());
context.addHttpRequestHandler(newMetricsHandler());
// Or set all at onceList<HttpRequestHandler> handlers = Arrays.asList(
newAuthHeaderHandler(),
newLoggingHandler(),
newMetricsHandler()
);
context.setHttpRequestHandlers(handlers);
httpClient.execute(context, httpRequest, responseHandler);

Response Processing

Working with HTTP Response

HttpResponseHandler<Object> handler = newHttpResponseHandler<Object>() {
@OverridepublicObjectonResponse(HttpResponsehttpResponse) {
// Get status codeintstatusCode = httpResponse.getStatusCode();
// Get headersMap<String, String> headers = httpResponse.getHeaders();
StringcontentType = headers.get("Content-Type");
// Get response body as stringStringbody = httpResponse.getBody();
// Parse as JSON ObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
// Parse as JSON ArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
returnbody;
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
};

JSON Response Parsing

// Parse as JSONObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
Stringname = jsonObject.getString("name");
intage = jsonObject.getInt("age");
// Parse as JSONArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
for (inti = 0; i < jsonArray.length(); i++) {
JSONObjectitem = jsonArray.getJSONObject(i);
// Process each item
}

Advanced Usage

Complete Example with All Features

importcom.javaquery.http.*;
importcom.javaquery.http.handler.*;
importcom.javaquery.http.retry.*;
publicclassAdvancedHttpClientExample {
publicstaticvoidmain(String[] args) {
// Build request with all optionsMap<String, String> headers = newHashMap<>();
headers.put("Authorization", "Bearer token123");
headers.put("Accept", "application/json");
Map<String, String> queryParams = newHashMap<>();
queryParams.put("page", "1");
queryParams.put("size", "20");
Stringpayload = "{\"action\":\"update\",\"data\":{\"status\":\"active\"}}";
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newDefaultBackoffStrategy(),
3
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("ComplexRequest", HttpMethod.POST)
.withHost("https://api.example.com")
.withPort(443)
.withEndPoint("/api/v1/resources")
.withHeaders(headers)
.withQueryParameter(queryParams)
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
payload
))
.withRetryPolicy(retryPolicy)
.build();
// Setup execution contextHttpExecutionContextcontext = newHttpExecutionContext();
Map<String, Object> metadata = newHashMap<>();
metadata.put("correlationId", UUID.randomUUID().toString());
metadata.put("requestSource", "backend-service");
context.setMetaData(metadata);
context.addHttpRequestHandler(newHttpRequestHandler() {
@OverridepublicvoidonRequest(HttpExecutionContextctx, HttpRequestreq) {
// Add request timestampreq.addHeader("X-Request-Timestamp", String.valueOf(System.currentTimeMillis()));
}
});
// Execute requestHttpClienthttpClient = newHttpClient();
Resultresult = httpClient.execute(context, request, newHttpResponseHandler<Result>() {
@OverridepublicResultonResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() >= 200 && httpResponse.getStatusCode() < 300) {
returnparseResult(httpResponse.getJSONObjectBody());
} else {
thrownewHttpException("Request failed: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Max retries reached. Status: {}", httpResponse.getStatusCode());
// Send alert, log to monitoring system, etc.
}
}
);
}
privatestaticResultparseResult(JSONObjectjson) {
// Parse JSON to Result objectreturnnewResult(json);
}
}

Handling Different Content Types

// JSON payloadHttpRequest.HttpPayloadjsonPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
"{\"key\":\"value\"}"
);
// Form dataMap<String, Object> formData = newHashMap<>();
formData.put("username", "john");
formData.put("password", "secret");
HttpRequest.HttpPayloadformPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
);
// Multipart form dataMap<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document");
HttpRequest.HttpPayloadmultipartPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
);
// Plain textHttpRequest.HttpPayloadtextPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"text/plain",
"Plain text content"
);
// XMLHttpRequest.HttpPayloadxmlPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/xml",
"<root><item>value</item></root>"
);

Error Handling

try {
httpClient.execute(context, request, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
intstatusCode = httpResponse.getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
returnhttpResponse.getBody();
} elseif (statusCode == 401) {
thrownewAuthenticationException("Authentication required");
} elseif (statusCode == 403) {
thrownewAuthorizationException("Access denied");
} elseif (statusCode == 404) {
thrownewResourceNotFoundException("Resource not found");
} elseif (statusCode >= 500) {
thrownewServerException("Server error: " + statusCode);
} else {
thrownewHttpException("HTTP error: " + statusCode);
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Log or alert when max retries exhaustedthrownewMaxRetriesExceededException(
"Failed after " + retryPolicy.getMaxErrorRetry() + " attempts"
);
}
});
} catch (AuthenticationExceptione) {
// Handle authentication error
} catch (ResourceNotFoundExceptione) {
// Handle not found
} catch (HttpExceptione) {
// Handle general HTTP errors
} catch (Exceptione) {
// Handle unexpected errors
}

Logging

The HTTP client uses SLF4J for logging and integrates with Logstash for structured logging. Request and response details are automatically logged with correlation information.

Enable Logging

Add to your logback.xml:

<configuration>
<appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender">
<encoderclass="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<loggername="com.javaquery.http"level="INFO" />
<rootlevel="INFO">
<appender-refref="CONSOLE" />
</root>
</configuration>

Logged information includes:

  • Request name and method
  • URL and endpoint
  • Headers and query parameters
  • Payload information
  • Response status code
  • Response time
  • Retry attempts
  • Metadata from execution context

API Reference

HttpRequest.HttpRequestBuilder

Builder for creating HTTP requests.

Methods:

  • withHost(String host) - Set the host URL
  • withPort(int port) - Set the port number
  • withEndPoint(String endPoint) - Set the endpoint path
  • withHeader(String key, String value) - Add a single header
  • withHeaders(Map<String, String> headers) - Add multiple headers
  • withQueryParameter(String key, String value) - Add a query parameter
  • withQueryParameter(Map<String, String> params) - Add multiple query parameters
  • withBasicAuth(String username, String password) - Set basic authentication
  • withHttpPayload(HttpPayload payload) - Set the request payload
  • withRetryPolicy(RetryPolicy policy) - Set retry policy
  • build() - Build the HttpRequest

HttpResponse

Response object containing status, headers, and body.

Methods:

  • int getStatusCode() - Get HTTP status code
  • Map<String, String> getHeaders() - Get response headers
  • String getBody() - Get response body as string
  • JSONObject getJSONObjectBody() - Parse body as JSON object
  • JSONArray getJSONArrayBody() - Parse body as JSON array

HttpClient

Main client for executing requests.

Methods:

  • <R> R execute(HttpExecutionContext context, HttpRequest request, HttpResponseHandler<R> handler) - Execute HTTP request

HttpExecutionContext

Context for request execution with metadata and handlers.

Methods:

  • void setMetaData(Map<String, Object> metaData) - Set metadata map
  • void addMetaData(String key, Object value) - Add single metadata entry
  • void addHttpRequestHandler(HttpRequestHandler handler) - Add request handler
  • void setHttpRequestHandlers(List<HttpRequestHandler> handlers) - Set multiple handlers

Requirements

  • Java 11 or higher
  • Apache HttpComponents 4.5.14
  • SLF4J 2.0.16
  • JSON 20250107
  • ScribeJava 8.3.3 (for OAuth)

Dependencies

This module depends on:

  • com.javaquery:util - Utility classes

License

This project is part of the JLite library suite.

Contributing

Contributions are welcome! Please ensure all tests pass before submitting pull requests.

Author

javaquery

Version

Current version: 1.0.7


For more information and updates, visit the JLite GitHub repository.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..

README.md

HTTP Client

A powerful and flexible HTTP client library for Java projects, built on top of Apache HttpComponents. This library provides a clean, fluent API for making HTTP requests with support for retries, OAuth authentication, custom handlers, and comprehensive logging.

Features

  • 🌐 Full HTTP Support - GET, POST, PUT, DELETE, and PATCH methods
  • 🔄 Retry Mechanism - Configurable retry policies with backoff strategies
  • 🔐 Authentication - Built-in support for Basic Auth and OAuth 1.0
  • 📝 Multiple Payload Types - JSON, Form data, Multipart, and String entities
  • 🎯 Request/Response Handlers - Extensible hooks for request and response processing
  • 📊 Structured Logging - Logstash integration for detailed request/response logging
  • ⚙️ Flexible Configuration - Custom headers, query parameters, and execution context
  • 🛠️ Error Handling - Comprehensive exception handling and retry mechanisms

Installation

Gradle

dependencies {
implementation 'com.javaquery:httpclient:1.0.7'
}

Maven

<dependency>
<groupId>com.javaquery</groupId>
<artifactId>httpclient</artifactId>
<version>1.0.7</version>
</dependency>

Quick Start

Simple GET Request

importcom.javaquery.http.*;
importcom.javaquery.http.handler.HttpResponseHandler;
// Build the requestHttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("GetUsers", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.build();
// Create execution contextHttpExecutionContextcontext = newHttpExecutionContext();
// Execute requestHttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
});

POST Request with JSON Payload

StringjsonPayload = "{\"name\":\"John Doe\",\"email\":\"john@example.com\"}";
HttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("CreateUser", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withHeader("Content-Type", "application/json")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8, "application/json", jsonPayload
))
.build();
HttpExecutionContextcontext = newHttpExecutionContext();
HttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<JSONObject>() {
@OverridepublicJSONObjectonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getJSONObjectBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
System.err.println("Max retries reached");
}
});

HTTP Methods

GET Request

HttpRequestgetRequest = newHttpRequest.HttpRequestBuilder("GetRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withQueryParameter("page", "1")
.withQueryParameter("size", "20")
.build();

POST Request with Form Data

Map<String, Object> formData = newHashMap<>();
formData.put("username", "john.doe");
formData.put("email", "john@example.com");
HttpRequestpostRequest = newHttpRequest.HttpRequestBuilder("PostForm", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/submit")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
))
.build();

POST Request with Multipart File Upload

Map<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document upload");
HttpRequestuploadRequest = newHttpRequest.HttpRequestBuilder("FileUpload", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/upload")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
))
.build();

PUT Request

StringupdatePayload = "{\"status\":\"active\"}";
HttpRequestputRequest = newHttpRequest.HttpRequestBuilder("UpdateUser", HttpMethod.PUT)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
updatePayload
))
.build();

DELETE Request

HttpRequestdeleteRequest = newHttpRequest.HttpRequestBuilder("DeleteUser", HttpMethod.DELETE)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.build();

Authentication

Basic Authentication

HttpRequestauthRequest = newHttpRequest.HttpRequestBuilder("SecureEndpoint", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/secure")
.withBasicAuth("username", "password")
.build();

OAuth 1.0

importcom.javaquery.http.oauth.OAuthConfig;
OAuthConfigoauthConfig = OAuthConfig.builder()
.consumerKey("your-consumer-key")
.consumerSecret("your-consumer-secret")
.accessToken("your-access-token")
.accessTokenSecret("your-access-token-secret")
.build();
HttpRequestoauthRequest = newHttpRequest.HttpRequestBuilder("OAuthRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/oauth/resource")
.build();
// Add OAuth handler to execution contextHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newOAuth10HttpRequestHandler(oauthConfig));
httpClient.execute(context, oauthRequest, responseHandler);

Headers and Query Parameters

Adding Headers

// Single headerHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeader("Authorization", "Bearer token123")
.withHeader("X-Custom-Header", "value")
.build();
// Multiple headersMap<String, String> headers = newHashMap<>();
headers.put("Content-Type", "application/json");
headers.put("Accept", "application/json");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeaders(headers)
.build();

Adding Query Parameters

// Single parameterHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/search")
.withQueryParameter("q", "java")
.withQueryParameter("limit", "10")
.build();
// Multiple parametersMap<String, String> params = newHashMap<>();
params.put("page", "1");
params.put("size", "20");
params.put("sort", "name");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withQueryParameter(params)
.build();

Retry Policies

Default Retry Policy

importcom.javaquery.http.DefaultRetryPolicy;
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("RetryRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/unstable")
.withRetryPolicy(DefaultRetryPolicy.get(3)) // Retry up to 3 times
.build();

Custom Retry Policy

importcom.javaquery.http.retry.*;
RetryPolicycustomRetry = newRetryPolicy(
newDefaultRetryCondition(), // When to retrynewDefaultBackoffStrategy(), // How long to wait between retries5// Max retry attempts
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("CustomRetry", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withRetryPolicy(customRetry)
.build();

Implementing Custom Retry Condition

importcom.javaquery.http.retry.RetryCondition;
publicclassCustomRetryConditionimplementsRetryCondition {
@OverridepublicbooleanshouldRetry(HttpRequestResponsehttpRequestResponse) {
HttpResponseresponse = httpRequestResponse.getHttpResponse();
// Retry on 5xx errors or specific 4xx errorsintstatusCode = response.getStatusCode();
returnstatusCode >= 500 || statusCode == 429 || statusCode == 408;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newCustomRetryCondition(),
newDefaultBackoffStrategy(),
3
);

Implementing Custom Backoff Strategy

importcom.javaquery.http.retry.BackoffStrategy;
publicclassExponentialBackoffimplementsBackoffStrategy {
@OverridepubliclongcomputeDelayBeforeNextRetry(HttpRequestResponsehttpRequestResponse, intretriesAttempted) {
// Exponential backoff: 2^attempt * 1000msreturn (long) Math.pow(2, retriesAttempted) * 1000;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newExponentialBackoff(),
5
);

Request and Response Handlers

Custom Request Handler

importcom.javaquery.http.handler.HttpRequestHandler;
publicclassCustomHeaderHandlerimplementsHttpRequestHandler {
@OverridepublicvoidonRequest(HttpExecutionContextcontext, HttpRequesthttpRequest) {
// Add custom headers before each requesthttpRequest.addHeader("X-Request-ID", UUID.randomUUID().toString());
httpRequest.addHeader("X-Timestamp", String.valueOf(System.currentTimeMillis()));
}
}
// Use the handlerHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newCustomHeaderHandler());
httpClient.execute(context, httpRequest, responseHandler);

Response Handler

importcom.javaquery.http.handler.HttpResponseHandler;
HttpResponseHandler<User> userHandler = newHttpResponseHandler<User>() {
@OverridepublicUseronResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() == 200) {
JSONObjectjson = httpResponse.getJSONObjectBody();
returnparseUser(json);
} elseif (httpResponse.getStatusCode() == 404) {
thrownewUserNotFoundException("User not found");
} else {
thrownewHttpException("Unexpected status: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Failed after maximum retry attempts. Status: {}", httpResponse.getStatusCode());
}
privateUserparseUser(JSONObjectjson) {
// Parse JSON to User objectreturnUser.builder()
.id(json.getLong("id"))
.name(json.getString("name"))
.email(json.getString("email"))
.build();
}
};

Execution Context

The HttpExecutionContext allows you to pass metadata and configure handlers for request execution.

Using Metadata

HttpExecutionContextcontext = newHttpExecutionContext();
// Add metadataMap<String, Object> metadata = newHashMap<>();
metadata.put("userId", "12345");
metadata.put("requestSource", "mobile-app");
context.setMetaData(metadata);
// Add individual metadatacontext.addMetaData("correlationId", UUID.randomUUID().toString());
httpClient.execute(context, httpRequest, responseHandler);

Multiple Request Handlers

HttpExecutionContextcontext = newHttpExecutionContext();
// Add multiple handlerscontext.addHttpRequestHandler(newAuthHeaderHandler());
context.addHttpRequestHandler(newLoggingHandler());
context.addHttpRequestHandler(newMetricsHandler());
// Or set all at onceList<HttpRequestHandler> handlers = Arrays.asList(
newAuthHeaderHandler(),
newLoggingHandler(),
newMetricsHandler()
);
context.setHttpRequestHandlers(handlers);
httpClient.execute(context, httpRequest, responseHandler);

Response Processing

Working with HTTP Response

HttpResponseHandler<Object> handler = newHttpResponseHandler<Object>() {
@OverridepublicObjectonResponse(HttpResponsehttpResponse) {
// Get status codeintstatusCode = httpResponse.getStatusCode();
// Get headersMap<String, String> headers = httpResponse.getHeaders();
StringcontentType = headers.get("Content-Type");
// Get response body as stringStringbody = httpResponse.getBody();
// Parse as JSON ObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
// Parse as JSON ArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
returnbody;
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
};

JSON Response Parsing

// Parse as JSONObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
Stringname = jsonObject.getString("name");
intage = jsonObject.getInt("age");
// Parse as JSONArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
for (inti = 0; i < jsonArray.length(); i++) {
JSONObjectitem = jsonArray.getJSONObject(i);
// Process each item
}

Advanced Usage

Complete Example with All Features

importcom.javaquery.http.*;
importcom.javaquery.http.handler.*;
importcom.javaquery.http.retry.*;
publicclassAdvancedHttpClientExample {
publicstaticvoidmain(String[] args) {
// Build request with all optionsMap<String, String> headers = newHashMap<>();
headers.put("Authorization", "Bearer token123");
headers.put("Accept", "application/json");
Map<String, String> queryParams = newHashMap<>();
queryParams.put("page", "1");
queryParams.put("size", "20");
Stringpayload = "{\"action\":\"update\",\"data\":{\"status\":\"active\"}}";
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newDefaultBackoffStrategy(),
3
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("ComplexRequest", HttpMethod.POST)
.withHost("https://api.example.com")
.withPort(443)
.withEndPoint("/api/v1/resources")
.withHeaders(headers)
.withQueryParameter(queryParams)
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
payload
))
.withRetryPolicy(retryPolicy)
.build();
// Setup execution contextHttpExecutionContextcontext = newHttpExecutionContext();
Map<String, Object> metadata = newHashMap<>();
metadata.put("correlationId", UUID.randomUUID().toString());
metadata.put("requestSource", "backend-service");
context.setMetaData(metadata);
context.addHttpRequestHandler(newHttpRequestHandler() {
@OverridepublicvoidonRequest(HttpExecutionContextctx, HttpRequestreq) {
// Add request timestampreq.addHeader("X-Request-Timestamp", String.valueOf(System.currentTimeMillis()));
}
});
// Execute requestHttpClienthttpClient = newHttpClient();
Resultresult = httpClient.execute(context, request, newHttpResponseHandler<Result>() {
@OverridepublicResultonResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() >= 200 && httpResponse.getStatusCode() < 300) {
returnparseResult(httpResponse.getJSONObjectBody());
} else {
thrownewHttpException("Request failed: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Max retries reached. Status: {}", httpResponse.getStatusCode());
// Send alert, log to monitoring system, etc.
}
}
);
}
privatestaticResultparseResult(JSONObjectjson) {
// Parse JSON to Result objectreturnnewResult(json);
}
}

Handling Different Content Types

// JSON payloadHttpRequest.HttpPayloadjsonPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
"{\"key\":\"value\"}"
);
// Form dataMap<String, Object> formData = newHashMap<>();
formData.put("username", "john");
formData.put("password", "secret");
HttpRequest.HttpPayloadformPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
);
// Multipart form dataMap<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document");
HttpRequest.HttpPayloadmultipartPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
);
// Plain textHttpRequest.HttpPayloadtextPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"text/plain",
"Plain text content"
);
// XMLHttpRequest.HttpPayloadxmlPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/xml",
"<root><item>value</item></root>"
);

Error Handling

try {
httpClient.execute(context, request, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
intstatusCode = httpResponse.getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
returnhttpResponse.getBody();
} elseif (statusCode == 401) {
thrownewAuthenticationException("Authentication required");
} elseif (statusCode == 403) {
thrownewAuthorizationException("Access denied");
} elseif (statusCode == 404) {
thrownewResourceNotFoundException("Resource not found");
} elseif (statusCode >= 500) {
thrownewServerException("Server error: " + statusCode);
} else {
thrownewHttpException("HTTP error: " + statusCode);
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Log or alert when max retries exhaustedthrownewMaxRetriesExceededException(
"Failed after " + retryPolicy.getMaxErrorRetry() + " attempts"
);
}
});
} catch (AuthenticationExceptione) {
// Handle authentication error
} catch (ResourceNotFoundExceptione) {
// Handle not found
} catch (HttpExceptione) {
// Handle general HTTP errors
} catch (Exceptione) {
// Handle unexpected errors
}

Logging

The HTTP client uses SLF4J for logging and integrates with Logstash for structured logging. Request and response details are automatically logged with correlation information.

Enable Logging

Add to your logback.xml:

<configuration>
<appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender">
<encoderclass="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<loggername="com.javaquery.http"level="INFO" />
<rootlevel="INFO">
<appender-refref="CONSOLE" />
</root>
</configuration>

Logged information includes:

  • Request name and method
  • URL and endpoint
  • Headers and query parameters
  • Payload information
  • Response status code
  • Response time
  • Retry attempts
  • Metadata from execution context

API Reference

HttpRequest.HttpRequestBuilder

Builder for creating HTTP requests.

Methods:

  • withHost(String host) - Set the host URL
  • withPort(int port) - Set the port number
  • withEndPoint(String endPoint) - Set the endpoint path
  • withHeader(String key, String value) - Add a single header
  • withHeaders(Map<String, String> headers) - Add multiple headers
  • withQueryParameter(String key, String value) - Add a query parameter
  • withQueryParameter(Map<String, String> params) - Add multiple query parameters
  • withBasicAuth(String username, String password) - Set basic authentication
  • withHttpPayload(HttpPayload payload) - Set the request payload
  • withRetryPolicy(RetryPolicy policy) - Set retry policy
  • build() - Build the HttpRequest

HttpResponse

Response object containing status, headers, and body.

Methods:

  • int getStatusCode() - Get HTTP status code
  • Map<String, String> getHeaders() - Get response headers
  • String getBody() - Get response body as string
  • JSONObject getJSONObjectBody() - Parse body as JSON object
  • JSONArray getJSONArrayBody() - Parse body as JSON array

HttpClient

Main client for executing requests.

Methods:

  • <R> R execute(HttpExecutionContext context, HttpRequest request, HttpResponseHandler<R> handler) - Execute HTTP request

HttpExecutionContext

Context for request execution with metadata and handlers.

Methods:

  • void setMetaData(Map<String, Object> metaData) - Set metadata map
  • void addMetaData(String key, Object value) - Add single metadata entry
  • void addHttpRequestHandler(HttpRequestHandler handler) - Add request handler
  • void setHttpRequestHandlers(List<HttpRequestHandler> handlers) - Set multiple handlers

Requirements

  • Java 11 or higher
  • Apache HttpComponents 4.5.14
  • SLF4J 2.0.16
  • JSON 20250107
  • ScribeJava 8.3.3 (for OAuth)

Dependencies

This module depends on:

  • com.javaquery:util - Utility classes

License

This project is part of the JLite library suite.

Contributing

Contributions are welcome! Please ensure all tests pass before submitting pull requests.

Author

javaquery

Version

Current version: 1.0.7


For more information and updates, visit the JLite GitHub repository.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..

README.md

HTTP Client

A powerful and flexible HTTP client library for Java projects, built on top of Apache HttpComponents. This library provides a clean, fluent API for making HTTP requests with support for retries, OAuth authentication, custom handlers, and comprehensive logging.

Features

  • 🌐 Full HTTP Support - GET, POST, PUT, DELETE, and PATCH methods
  • 🔄 Retry Mechanism - Configurable retry policies with backoff strategies
  • 🔐 Authentication - Built-in support for Basic Auth and OAuth 1.0
  • 📝 Multiple Payload Types - JSON, Form data, Multipart, and String entities
  • 🎯 Request/Response Handlers - Extensible hooks for request and response processing
  • 📊 Structured Logging - Logstash integration for detailed request/response logging
  • ⚙️ Flexible Configuration - Custom headers, query parameters, and execution context
  • 🛠️ Error Handling - Comprehensive exception handling and retry mechanisms

Installation

Gradle

dependencies {
implementation 'com.javaquery:httpclient:1.0.7'
}

Maven

<dependency>
<groupId>com.javaquery</groupId>
<artifactId>httpclient</artifactId>
<version>1.0.7</version>
</dependency>

Quick Start

Simple GET Request

importcom.javaquery.http.*;
importcom.javaquery.http.handler.HttpResponseHandler;
// Build the requestHttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("GetUsers", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.build();
// Create execution contextHttpExecutionContextcontext = newHttpExecutionContext();
// Execute requestHttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
});

POST Request with JSON Payload

StringjsonPayload = "{\"name\":\"John Doe\",\"email\":\"john@example.com\"}";
HttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("CreateUser", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withHeader("Content-Type", "application/json")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8, "application/json", jsonPayload
))
.build();
HttpExecutionContextcontext = newHttpExecutionContext();
HttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<JSONObject>() {
@OverridepublicJSONObjectonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getJSONObjectBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
System.err.println("Max retries reached");
}
});

HTTP Methods

GET Request

HttpRequestgetRequest = newHttpRequest.HttpRequestBuilder("GetRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withQueryParameter("page", "1")
.withQueryParameter("size", "20")
.build();

POST Request with Form Data

Map<String, Object> formData = newHashMap<>();
formData.put("username", "john.doe");
formData.put("email", "john@example.com");
HttpRequestpostRequest = newHttpRequest.HttpRequestBuilder("PostForm", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/submit")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
))
.build();

POST Request with Multipart File Upload

Map<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document upload");
HttpRequestuploadRequest = newHttpRequest.HttpRequestBuilder("FileUpload", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/upload")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
))
.build();

PUT Request

StringupdatePayload = "{\"status\":\"active\"}";
HttpRequestputRequest = newHttpRequest.HttpRequestBuilder("UpdateUser", HttpMethod.PUT)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
updatePayload
))
.build();

DELETE Request

HttpRequestdeleteRequest = newHttpRequest.HttpRequestBuilder("DeleteUser", HttpMethod.DELETE)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.build();

Authentication

Basic Authentication

HttpRequestauthRequest = newHttpRequest.HttpRequestBuilder("SecureEndpoint", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/secure")
.withBasicAuth("username", "password")
.build();

OAuth 1.0

importcom.javaquery.http.oauth.OAuthConfig;
OAuthConfigoauthConfig = OAuthConfig.builder()
.consumerKey("your-consumer-key")
.consumerSecret("your-consumer-secret")
.accessToken("your-access-token")
.accessTokenSecret("your-access-token-secret")
.build();
HttpRequestoauthRequest = newHttpRequest.HttpRequestBuilder("OAuthRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/oauth/resource")
.build();
// Add OAuth handler to execution contextHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newOAuth10HttpRequestHandler(oauthConfig));
httpClient.execute(context, oauthRequest, responseHandler);

Headers and Query Parameters

Adding Headers

// Single headerHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeader("Authorization", "Bearer token123")
.withHeader("X-Custom-Header", "value")
.build();
// Multiple headersMap<String, String> headers = newHashMap<>();
headers.put("Content-Type", "application/json");
headers.put("Accept", "application/json");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeaders(headers)
.build();

Adding Query Parameters

// Single parameterHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/search")
.withQueryParameter("q", "java")
.withQueryParameter("limit", "10")
.build();
// Multiple parametersMap<String, String> params = newHashMap<>();
params.put("page", "1");
params.put("size", "20");
params.put("sort", "name");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withQueryParameter(params)
.build();

Retry Policies

Default Retry Policy

importcom.javaquery.http.DefaultRetryPolicy;
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("RetryRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/unstable")
.withRetryPolicy(DefaultRetryPolicy.get(3)) // Retry up to 3 times
.build();

Custom Retry Policy

importcom.javaquery.http.retry.*;
RetryPolicycustomRetry = newRetryPolicy(
newDefaultRetryCondition(), // When to retrynewDefaultBackoffStrategy(), // How long to wait between retries5// Max retry attempts
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("CustomRetry", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withRetryPolicy(customRetry)
.build();

Implementing Custom Retry Condition

importcom.javaquery.http.retry.RetryCondition;
publicclassCustomRetryConditionimplementsRetryCondition {
@OverridepublicbooleanshouldRetry(HttpRequestResponsehttpRequestResponse) {
HttpResponseresponse = httpRequestResponse.getHttpResponse();
// Retry on 5xx errors or specific 4xx errorsintstatusCode = response.getStatusCode();
returnstatusCode >= 500 || statusCode == 429 || statusCode == 408;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newCustomRetryCondition(),
newDefaultBackoffStrategy(),
3
);

Implementing Custom Backoff Strategy

importcom.javaquery.http.retry.BackoffStrategy;
publicclassExponentialBackoffimplementsBackoffStrategy {
@OverridepubliclongcomputeDelayBeforeNextRetry(HttpRequestResponsehttpRequestResponse, intretriesAttempted) {
// Exponential backoff: 2^attempt * 1000msreturn (long) Math.pow(2, retriesAttempted) * 1000;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newExponentialBackoff(),
5
);

Request and Response Handlers

Custom Request Handler

importcom.javaquery.http.handler.HttpRequestHandler;
publicclassCustomHeaderHandlerimplementsHttpRequestHandler {
@OverridepublicvoidonRequest(HttpExecutionContextcontext, HttpRequesthttpRequest) {
// Add custom headers before each requesthttpRequest.addHeader("X-Request-ID", UUID.randomUUID().toString());
httpRequest.addHeader("X-Timestamp", String.valueOf(System.currentTimeMillis()));
}
}
// Use the handlerHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newCustomHeaderHandler());
httpClient.execute(context, httpRequest, responseHandler);

Response Handler

importcom.javaquery.http.handler.HttpResponseHandler;
HttpResponseHandler<User> userHandler = newHttpResponseHandler<User>() {
@OverridepublicUseronResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() == 200) {
JSONObjectjson = httpResponse.getJSONObjectBody();
returnparseUser(json);
} elseif (httpResponse.getStatusCode() == 404) {
thrownewUserNotFoundException("User not found");
} else {
thrownewHttpException("Unexpected status: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Failed after maximum retry attempts. Status: {}", httpResponse.getStatusCode());
}
privateUserparseUser(JSONObjectjson) {
// Parse JSON to User objectreturnUser.builder()
.id(json.getLong("id"))
.name(json.getString("name"))
.email(json.getString("email"))
.build();
}
};

Execution Context

The HttpExecutionContext allows you to pass metadata and configure handlers for request execution.

Using Metadata

HttpExecutionContextcontext = newHttpExecutionContext();
// Add metadataMap<String, Object> metadata = newHashMap<>();
metadata.put("userId", "12345");
metadata.put("requestSource", "mobile-app");
context.setMetaData(metadata);
// Add individual metadatacontext.addMetaData("correlationId", UUID.randomUUID().toString());
httpClient.execute(context, httpRequest, responseHandler);

Multiple Request Handlers

HttpExecutionContextcontext = newHttpExecutionContext();
// Add multiple handlerscontext.addHttpRequestHandler(newAuthHeaderHandler());
context.addHttpRequestHandler(newLoggingHandler());
context.addHttpRequestHandler(newMetricsHandler());
// Or set all at onceList<HttpRequestHandler> handlers = Arrays.asList(
newAuthHeaderHandler(),
newLoggingHandler(),
newMetricsHandler()
);
context.setHttpRequestHandlers(handlers);
httpClient.execute(context, httpRequest, responseHandler);

Response Processing

Working with HTTP Response

HttpResponseHandler<Object> handler = newHttpResponseHandler<Object>() {
@OverridepublicObjectonResponse(HttpResponsehttpResponse) {
// Get status codeintstatusCode = httpResponse.getStatusCode();
// Get headersMap<String, String> headers = httpResponse.getHeaders();
StringcontentType = headers.get("Content-Type");
// Get response body as stringStringbody = httpResponse.getBody();
// Parse as JSON ObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
// Parse as JSON ArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
returnbody;
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
};

JSON Response Parsing

// Parse as JSONObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
Stringname = jsonObject.getString("name");
intage = jsonObject.getInt("age");
// Parse as JSONArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
for (inti = 0; i < jsonArray.length(); i++) {
JSONObjectitem = jsonArray.getJSONObject(i);
// Process each item
}

Advanced Usage

Complete Example with All Features

importcom.javaquery.http.*;
importcom.javaquery.http.handler.*;
importcom.javaquery.http.retry.*;
publicclassAdvancedHttpClientExample {
publicstaticvoidmain(String[] args) {
// Build request with all optionsMap<String, String> headers = newHashMap<>();
headers.put("Authorization", "Bearer token123");
headers.put("Accept", "application/json");
Map<String, String> queryParams = newHashMap<>();
queryParams.put("page", "1");
queryParams.put("size", "20");
Stringpayload = "{\"action\":\"update\",\"data\":{\"status\":\"active\"}}";
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newDefaultBackoffStrategy(),
3
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("ComplexRequest", HttpMethod.POST)
.withHost("https://api.example.com")
.withPort(443)
.withEndPoint("/api/v1/resources")
.withHeaders(headers)
.withQueryParameter(queryParams)
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
payload
))
.withRetryPolicy(retryPolicy)
.build();
// Setup execution contextHttpExecutionContextcontext = newHttpExecutionContext();
Map<String, Object> metadata = newHashMap<>();
metadata.put("correlationId", UUID.randomUUID().toString());
metadata.put("requestSource", "backend-service");
context.setMetaData(metadata);
context.addHttpRequestHandler(newHttpRequestHandler() {
@OverridepublicvoidonRequest(HttpExecutionContextctx, HttpRequestreq) {
// Add request timestampreq.addHeader("X-Request-Timestamp", String.valueOf(System.currentTimeMillis()));
}
});
// Execute requestHttpClienthttpClient = newHttpClient();
Resultresult = httpClient.execute(context, request, newHttpResponseHandler<Result>() {
@OverridepublicResultonResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() >= 200 && httpResponse.getStatusCode() < 300) {
returnparseResult(httpResponse.getJSONObjectBody());
} else {
thrownewHttpException("Request failed: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Max retries reached. Status: {}", httpResponse.getStatusCode());
// Send alert, log to monitoring system, etc.
}
}
);
}
privatestaticResultparseResult(JSONObjectjson) {
// Parse JSON to Result objectreturnnewResult(json);
}
}

Handling Different Content Types

// JSON payloadHttpRequest.HttpPayloadjsonPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
"{\"key\":\"value\"}"
);
// Form dataMap<String, Object> formData = newHashMap<>();
formData.put("username", "john");
formData.put("password", "secret");
HttpRequest.HttpPayloadformPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
);
// Multipart form dataMap<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document");
HttpRequest.HttpPayloadmultipartPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
);
// Plain textHttpRequest.HttpPayloadtextPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"text/plain",
"Plain text content"
);
// XMLHttpRequest.HttpPayloadxmlPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/xml",
"<root><item>value</item></root>"
);

Error Handling

try {
httpClient.execute(context, request, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
intstatusCode = httpResponse.getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
returnhttpResponse.getBody();
} elseif (statusCode == 401) {
thrownewAuthenticationException("Authentication required");
} elseif (statusCode == 403) {
thrownewAuthorizationException("Access denied");
} elseif (statusCode == 404) {
thrownewResourceNotFoundException("Resource not found");
} elseif (statusCode >= 500) {
thrownewServerException("Server error: " + statusCode);
} else {
thrownewHttpException("HTTP error: " + statusCode);
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Log or alert when max retries exhaustedthrownewMaxRetriesExceededException(
"Failed after " + retryPolicy.getMaxErrorRetry() + " attempts"
);
}
});
} catch (AuthenticationExceptione) {
// Handle authentication error
} catch (ResourceNotFoundExceptione) {
// Handle not found
} catch (HttpExceptione) {
// Handle general HTTP errors
} catch (Exceptione) {
// Handle unexpected errors
}

Logging

The HTTP client uses SLF4J for logging and integrates with Logstash for structured logging. Request and response details are automatically logged with correlation information.

Enable Logging

Add to your logback.xml:

<configuration>
<appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender">
<encoderclass="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<loggername="com.javaquery.http"level="INFO" />
<rootlevel="INFO">
<appender-refref="CONSOLE" />
</root>
</configuration>

Logged information includes:

  • Request name and method
  • URL and endpoint
  • Headers and query parameters
  • Payload information
  • Response status code
  • Response time
  • Retry attempts
  • Metadata from execution context

API Reference

HttpRequest.HttpRequestBuilder

Builder for creating HTTP requests.

Methods:

  • withHost(String host) - Set the host URL
  • withPort(int port) - Set the port number
  • withEndPoint(String endPoint) - Set the endpoint path
  • withHeader(String key, String value) - Add a single header
  • withHeaders(Map<String, String> headers) - Add multiple headers
  • withQueryParameter(String key, String value) - Add a query parameter
  • withQueryParameter(Map<String, String> params) - Add multiple query parameters
  • withBasicAuth(String username, String password) - Set basic authentication
  • withHttpPayload(HttpPayload payload) - Set the request payload
  • withRetryPolicy(RetryPolicy policy) - Set retry policy
  • build() - Build the HttpRequest

HttpResponse

Response object containing status, headers, and body.

Methods:

  • int getStatusCode() - Get HTTP status code
  • Map<String, String> getHeaders() - Get response headers
  • String getBody() - Get response body as string
  • JSONObject getJSONObjectBody() - Parse body as JSON object
  • JSONArray getJSONArrayBody() - Parse body as JSON array

HttpClient

Main client for executing requests.

Methods:

  • <R> R execute(HttpExecutionContext context, HttpRequest request, HttpResponseHandler<R> handler) - Execute HTTP request

HttpExecutionContext

Context for request execution with metadata and handlers.

Methods:

  • void setMetaData(Map<String, Object> metaData) - Set metadata map
  • void addMetaData(String key, Object value) - Add single metadata entry
  • void addHttpRequestHandler(HttpRequestHandler handler) - Add request handler
  • void setHttpRequestHandlers(List<HttpRequestHandler> handlers) - Set multiple handlers

Requirements

  • Java 11 or higher
  • Apache HttpComponents 4.5.14
  • SLF4J 2.0.16
  • JSON 20250107
  • ScribeJava 8.3.3 (for OAuth)

Dependencies

This module depends on:

  • com.javaquery:util - Utility classes

License

This project is part of the JLite library suite.

Contributing

Contributions are welcome! Please ensure all tests pass before submitting pull requests.

Author

javaquery

Version

Current version: 1.0.7


For more information and updates, visit the JLite GitHub repository.

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..

README.md

HTTP Client

A powerful and flexible HTTP client library for Java projects, built on top of Apache HttpComponents. This library provides a clean, fluent API for making HTTP requests with support for retries, OAuth authentication, custom handlers, and comprehensive logging.

Features

  • 🌐 Full HTTP Support - GET, POST, PUT, DELETE, and PATCH methods
  • 🔄 Retry Mechanism - Configurable retry policies with backoff strategies
  • 🔐 Authentication - Built-in support for Basic Auth and OAuth 1.0
  • 📝 Multiple Payload Types - JSON, Form data, Multipart, and String entities
  • 🎯 Request/Response Handlers - Extensible hooks for request and response processing
  • 📊 Structured Logging - Logstash integration for detailed request/response logging
  • ⚙️ Flexible Configuration - Custom headers, query parameters, and execution context
  • 🛠️ Error Handling - Comprehensive exception handling and retry mechanisms

Installation

Gradle

dependencies {
implementation 'com.javaquery:httpclient:1.0.7'
}

Maven

<dependency>
<groupId>com.javaquery</groupId>
<artifactId>httpclient</artifactId>
<version>1.0.7</version>
</dependency>

Quick Start

Simple GET Request

importcom.javaquery.http.*;
importcom.javaquery.http.handler.HttpResponseHandler;
// Build the requestHttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("GetUsers", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.build();
// Create execution contextHttpExecutionContextcontext = newHttpExecutionContext();
// Execute requestHttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
});

POST Request with JSON Payload

StringjsonPayload = "{\"name\":\"John Doe\",\"email\":\"john@example.com\"}";
HttpRequesthttpRequest = newHttpRequest.HttpRequestBuilder("CreateUser", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withHeader("Content-Type", "application/json")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8, "application/json", jsonPayload
))
.build();
HttpExecutionContextcontext = newHttpExecutionContext();
HttpClienthttpClient = newHttpClient();
httpClient.execute(context, httpRequest, newHttpResponseHandler<JSONObject>() {
@OverridepublicJSONObjectonResponse(HttpResponsehttpResponse) {
returnhttpResponse.getJSONObjectBody();
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
System.err.println("Max retries reached");
}
});

HTTP Methods

GET Request

HttpRequestgetRequest = newHttpRequest.HttpRequestBuilder("GetRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withQueryParameter("page", "1")
.withQueryParameter("size", "20")
.build();

POST Request with Form Data

Map<String, Object> formData = newHashMap<>();
formData.put("username", "john.doe");
formData.put("email", "john@example.com");
HttpRequestpostRequest = newHttpRequest.HttpRequestBuilder("PostForm", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/submit")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
))
.build();

POST Request with Multipart File Upload

Map<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document upload");
HttpRequestuploadRequest = newHttpRequest.HttpRequestBuilder("FileUpload", HttpMethod.POST)
.withHost("https://api.example.com")
.withEndPoint("/upload")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
))
.build();

PUT Request

StringupdatePayload = "{\"status\":\"active\"}";
HttpRequestputRequest = newHttpRequest.HttpRequestBuilder("UpdateUser", HttpMethod.PUT)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
updatePayload
))
.build();

DELETE Request

HttpRequestdeleteRequest = newHttpRequest.HttpRequestBuilder("DeleteUser", HttpMethod.DELETE)
.withHost("https://api.example.com")
.withEndPoint("/users/123")
.build();

Authentication

Basic Authentication

HttpRequestauthRequest = newHttpRequest.HttpRequestBuilder("SecureEndpoint", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/secure")
.withBasicAuth("username", "password")
.build();

OAuth 1.0

importcom.javaquery.http.oauth.OAuthConfig;
OAuthConfigoauthConfig = OAuthConfig.builder()
.consumerKey("your-consumer-key")
.consumerSecret("your-consumer-secret")
.accessToken("your-access-token")
.accessTokenSecret("your-access-token-secret")
.build();
HttpRequestoauthRequest = newHttpRequest.HttpRequestBuilder("OAuthRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/oauth/resource")
.build();
// Add OAuth handler to execution contextHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newOAuth10HttpRequestHandler(oauthConfig));
httpClient.execute(context, oauthRequest, responseHandler);

Headers and Query Parameters

Adding Headers

// Single headerHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeader("Authorization", "Bearer token123")
.withHeader("X-Custom-Header", "value")
.build();
// Multiple headersMap<String, String> headers = newHashMap<>();
headers.put("Content-Type", "application/json");
headers.put("Accept", "application/json");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withHeaders(headers)
.build();

Adding Query Parameters

// Single parameterHttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/search")
.withQueryParameter("q", "java")
.withQueryParameter("limit", "10")
.build();
// Multiple parametersMap<String, String> params = newHashMap<>();
params.put("page", "1");
params.put("size", "20");
params.put("sort", "name");
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("Request", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/users")
.withQueryParameter(params)
.build();

Retry Policies

Default Retry Policy

importcom.javaquery.http.DefaultRetryPolicy;
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("RetryRequest", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/unstable")
.withRetryPolicy(DefaultRetryPolicy.get(3)) // Retry up to 3 times
.build();

Custom Retry Policy

importcom.javaquery.http.retry.*;
RetryPolicycustomRetry = newRetryPolicy(
newDefaultRetryCondition(), // When to retrynewDefaultBackoffStrategy(), // How long to wait between retries5// Max retry attempts
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("CustomRetry", HttpMethod.GET)
.withHost("https://api.example.com")
.withEndPoint("/resource")
.withRetryPolicy(customRetry)
.build();

Implementing Custom Retry Condition

importcom.javaquery.http.retry.RetryCondition;
publicclassCustomRetryConditionimplementsRetryCondition {
@OverridepublicbooleanshouldRetry(HttpRequestResponsehttpRequestResponse) {
HttpResponseresponse = httpRequestResponse.getHttpResponse();
// Retry on 5xx errors or specific 4xx errorsintstatusCode = response.getStatusCode();
returnstatusCode >= 500 || statusCode == 429 || statusCode == 408;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newCustomRetryCondition(),
newDefaultBackoffStrategy(),
3
);

Implementing Custom Backoff Strategy

importcom.javaquery.http.retry.BackoffStrategy;
publicclassExponentialBackoffimplementsBackoffStrategy {
@OverridepubliclongcomputeDelayBeforeNextRetry(HttpRequestResponsehttpRequestResponse, intretriesAttempted) {
// Exponential backoff: 2^attempt * 1000msreturn (long) Math.pow(2, retriesAttempted) * 1000;
}
}
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newExponentialBackoff(),
5
);

Request and Response Handlers

Custom Request Handler

importcom.javaquery.http.handler.HttpRequestHandler;
publicclassCustomHeaderHandlerimplementsHttpRequestHandler {
@OverridepublicvoidonRequest(HttpExecutionContextcontext, HttpRequesthttpRequest) {
// Add custom headers before each requesthttpRequest.addHeader("X-Request-ID", UUID.randomUUID().toString());
httpRequest.addHeader("X-Timestamp", String.valueOf(System.currentTimeMillis()));
}
}
// Use the handlerHttpExecutionContextcontext = newHttpExecutionContext();
context.addHttpRequestHandler(newCustomHeaderHandler());
httpClient.execute(context, httpRequest, responseHandler);

Response Handler

importcom.javaquery.http.handler.HttpResponseHandler;
HttpResponseHandler<User> userHandler = newHttpResponseHandler<User>() {
@OverridepublicUseronResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() == 200) {
JSONObjectjson = httpResponse.getJSONObjectBody();
returnparseUser(json);
} elseif (httpResponse.getStatusCode() == 404) {
thrownewUserNotFoundException("User not found");
} else {
thrownewHttpException("Unexpected status: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Failed after maximum retry attempts. Status: {}", httpResponse.getStatusCode());
}
privateUserparseUser(JSONObjectjson) {
// Parse JSON to User objectreturnUser.builder()
.id(json.getLong("id"))
.name(json.getString("name"))
.email(json.getString("email"))
.build();
}
};

Execution Context

The HttpExecutionContext allows you to pass metadata and configure handlers for request execution.

Using Metadata

HttpExecutionContextcontext = newHttpExecutionContext();
// Add metadataMap<String, Object> metadata = newHashMap<>();
metadata.put("userId", "12345");
metadata.put("requestSource", "mobile-app");
context.setMetaData(metadata);
// Add individual metadatacontext.addMetaData("correlationId", UUID.randomUUID().toString());
httpClient.execute(context, httpRequest, responseHandler);

Multiple Request Handlers

HttpExecutionContextcontext = newHttpExecutionContext();
// Add multiple handlerscontext.addHttpRequestHandler(newAuthHeaderHandler());
context.addHttpRequestHandler(newLoggingHandler());
context.addHttpRequestHandler(newMetricsHandler());
// Or set all at onceList<HttpRequestHandler> handlers = Arrays.asList(
newAuthHeaderHandler(),
newLoggingHandler(),
newMetricsHandler()
);
context.setHttpRequestHandlers(handlers);
httpClient.execute(context, httpRequest, responseHandler);

Response Processing

Working with HTTP Response

HttpResponseHandler<Object> handler = newHttpResponseHandler<Object>() {
@OverridepublicObjectonResponse(HttpResponsehttpResponse) {
// Get status codeintstatusCode = httpResponse.getStatusCode();
// Get headersMap<String, String> headers = httpResponse.getHeaders();
StringcontentType = headers.get("Content-Type");
// Get response body as stringStringbody = httpResponse.getBody();
// Parse as JSON ObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
// Parse as JSON ArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
returnbody;
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Handle max retry scenario
}
};

JSON Response Parsing

// Parse as JSONObjectJSONObjectjsonObject = httpResponse.getJSONObjectBody();
Stringname = jsonObject.getString("name");
intage = jsonObject.getInt("age");
// Parse as JSONArrayJSONArrayjsonArray = httpResponse.getJSONArrayBody();
for (inti = 0; i < jsonArray.length(); i++) {
JSONObjectitem = jsonArray.getJSONObject(i);
// Process each item
}

Advanced Usage

Complete Example with All Features

importcom.javaquery.http.*;
importcom.javaquery.http.handler.*;
importcom.javaquery.http.retry.*;
publicclassAdvancedHttpClientExample {
publicstaticvoidmain(String[] args) {
// Build request with all optionsMap<String, String> headers = newHashMap<>();
headers.put("Authorization", "Bearer token123");
headers.put("Accept", "application/json");
Map<String, String> queryParams = newHashMap<>();
queryParams.put("page", "1");
queryParams.put("size", "20");
Stringpayload = "{\"action\":\"update\",\"data\":{\"status\":\"active\"}}";
RetryPolicyretryPolicy = newRetryPolicy(
newDefaultRetryCondition(),
newDefaultBackoffStrategy(),
3
);
HttpRequestrequest = newHttpRequest.HttpRequestBuilder("ComplexRequest", HttpMethod.POST)
.withHost("https://api.example.com")
.withPort(443)
.withEndPoint("/api/v1/resources")
.withHeaders(headers)
.withQueryParameter(queryParams)
.withHttpPayload(newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
payload
))
.withRetryPolicy(retryPolicy)
.build();
// Setup execution contextHttpExecutionContextcontext = newHttpExecutionContext();
Map<String, Object> metadata = newHashMap<>();
metadata.put("correlationId", UUID.randomUUID().toString());
metadata.put("requestSource", "backend-service");
context.setMetaData(metadata);
context.addHttpRequestHandler(newHttpRequestHandler() {
@OverridepublicvoidonRequest(HttpExecutionContextctx, HttpRequestreq) {
// Add request timestampreq.addHeader("X-Request-Timestamp", String.valueOf(System.currentTimeMillis()));
}
});
// Execute requestHttpClienthttpClient = newHttpClient();
Resultresult = httpClient.execute(context, request, newHttpResponseHandler<Result>() {
@OverridepublicResultonResponse(HttpResponsehttpResponse) {
if (httpResponse.getStatusCode() >= 200 && httpResponse.getStatusCode() < 300) {
returnparseResult(httpResponse.getJSONObjectBody());
} else {
thrownewHttpException("Request failed: " + httpResponse.getStatusCode());
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
LOGGER.error("Max retries reached. Status: {}", httpResponse.getStatusCode());
// Send alert, log to monitoring system, etc.
}
}
);
}
privatestaticResultparseResult(JSONObjectjson) {
// Parse JSON to Result objectreturnnewResult(json);
}
}

Handling Different Content Types

// JSON payloadHttpRequest.HttpPayloadjsonPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/json",
"{\"key\":\"value\"}"
);
// Form dataMap<String, Object> formData = newHashMap<>();
formData.put("username", "john");
formData.put("password", "secret");
HttpRequest.HttpPayloadformPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/x-www-form-urlencoded",
formData
);
// Multipart form dataMap<String, Object> multipartData = newHashMap<>();
multipartData.put("file", newFile("/path/to/file.pdf"));
multipartData.put("description", "Document");
HttpRequest.HttpPayloadmultipartPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"multipart/form-data",
multipartData
);
// Plain textHttpRequest.HttpPayloadtextPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"text/plain",
"Plain text content"
);
// XMLHttpRequest.HttpPayloadxmlPayload = newHttpRequest.HttpPayload(
StringPool.UTF8,
"application/xml",
"<root><item>value</item></root>"
);

Error Handling

try {
httpClient.execute(context, request, newHttpResponseHandler<String>() {
@OverridepublicStringonResponse(HttpResponsehttpResponse) {
intstatusCode = httpResponse.getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
returnhttpResponse.getBody();
} elseif (statusCode == 401) {
thrownewAuthenticationException("Authentication required");
} elseif (statusCode == 403) {
thrownewAuthorizationException("Access denied");
} elseif (statusCode == 404) {
thrownewResourceNotFoundException("Resource not found");
} elseif (statusCode >= 500) {
thrownewServerException("Server error: " + statusCode);
} else {
thrownewHttpException("HTTP error: " + statusCode);
}
}
@OverridepublicvoidonMaxRetryAttempted(HttpResponsehttpResponse) {
// Log or alert when max retries exhaustedthrownewMaxRetriesExceededException(
"Failed after " + retryPolicy.getMaxErrorRetry() + " attempts"
);
}
});
} catch (AuthenticationExceptione) {
// Handle authentication error
} catch (ResourceNotFoundExceptione) {
// Handle not found
} catch (HttpExceptione) {
// Handle general HTTP errors
} catch (Exceptione) {
// Handle unexpected errors
}

Logging

The HTTP client uses SLF4J for logging and integrates with Logstash for structured logging. Request and response details are automatically logged with correlation information.

Enable Logging

Add to your logback.xml:

<configuration>
<appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender">
<encoderclass="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<loggername="com.javaquery.http"level="INFO" />
<rootlevel="INFO">
<appender-refref="CONSOLE" />
</root>
</configuration>

Logged information includes:

  • Request name and method
  • URL and endpoint
  • Headers and query parameters
  • Payload information
  • Response status code
  • Response time
  • Retry attempts
  • Metadata from execution context

API Reference

HttpRequest.HttpRequestBuilder

Builder for creating HTTP requests.

Methods:

  • withHost(String host) - Set the host URL
  • withPort(int port) - Set the port number
  • withEndPoint(String endPoint) - Set the endpoint path
  • withHeader(String key, String value) - Add a single header
  • withHeaders(Map<String, String> headers) - Add multiple headers
  • withQueryParameter(String key, String value) - Add a query parameter
  • withQueryParameter(Map<String, String> params) - Add multiple query parameters
  • withBasicAuth(String username, String password) - Set basic authentication
  • withHttpPayload(HttpPayload payload) - Set the request payload
  • withRetryPolicy(RetryPolicy policy) - Set retry policy
  • build() - Build the HttpRequest

HttpResponse

Response object containing status, headers, and body.

Methods:

  • int getStatusCode() - Get HTTP status code
  • Map<String, String> getHeaders() - Get response headers
  • String getBody() - Get response body as string
  • JSONObject getJSONObjectBody() - Parse body as JSON object
  • JSONArray getJSONArrayBody() - Parse body as JSON array

HttpClient

Main client for executing requests.

Methods:

  • <R> R execute(HttpExecutionContext context, HttpRequest request, HttpResponseHandler<R> handler) - Execute HTTP request

HttpExecutionContext

Context for request execution with metadata and handlers.

Methods:

  • void setMetaData(Map<String, Object> metaData) - Set metadata map
  • void addMetaData(String key, Object value) - Add single metadata entry
  • void addHttpRequestHandler(HttpRequestHandler handler) - Add request handler
  • void setHttpRequestHandlers(List<HttpRequestHandler> handlers) - Set multiple handlers

Requirements

  • Java 11 or higher
  • Apache HttpComponents 4.5.14
  • SLF4J 2.0.16
  • JSON 20250107
  • ScribeJava 8.3.3 (for OAuth)

Dependencies

This module depends on:

  • com.javaquery:util - Utility classes

License

This project is part of the JLite library suite.

Contributing

Contributions are welcome! Please ensure all tests pass before submitting pull requests.

Author

javaquery

Version

Current version: 1.0.7


For more information and updates, visit the JLite GitHub repository.