{"id":45190830,"url":"https://github.com/jsunsoftware/http-request","last_synced_at":"2026-02-20T12:03:07.760Z","repository":{"id":46375337,"uuid":"102000216","full_name":"jsunsoftware/http-request","owner":"jsunsoftware","description":"Enhancing/simplify apache http client","archived":false,"fork":false,"pushed_at":"2026-02-17T18:08:17.000Z","size":531,"stargazers_count":14,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-17T21:42:28.831Z","etag":null,"topics":["apache-httpcomponents","connection-pool","deserialization","http-client","http-requests","httprequest","supported-converting"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jsunsoftware.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-08-31T12:50:46.000Z","updated_at":"2026-02-17T17:42:24.000Z","dependencies_parsed_at":"2026-01-06T05:08:01.555Z","dependency_job_id":null,"html_url":"https://github.com/jsunsoftware/http-request","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/jsunsoftware/http-request","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsunsoftware%2Fhttp-request","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsunsoftware%2Fhttp-request/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsunsoftware%2Fhttp-request/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsunsoftware%2Fhttp-request/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jsunsoftware","download_url":"https://codeload.github.com/jsunsoftware/http-request/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsunsoftware%2Fhttp-request/sbom","scorecard":{"id":539633,"data":{"date":"2025-08-11","repo":{"name":"github.com/jsunsoftware/http-request","commit":"0b4f23c56245e7831690294e2673963208225f6c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.8,"checks":[{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":9,"reason":"11 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 9","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-20T07:53:22.570Z","repository_id":46375337,"created_at":"2025-08-20T07:53:22.570Z","updated_at":"2025-08-20T07:53:22.570Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29650504,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T09:27:29.698Z","status":"ssl_error","status_checked_at":"2026-02-20T09:26:12.373Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apache-httpcomponents","connection-pool","deserialization","http-client","http-requests","httprequest","supported-converting"],"created_at":"2026-02-20T12:03:07.692Z","updated_at":"2026-02-20T12:03:07.752Z","avatar_url":"https://github.com/jsunsoftware.png","language":"Java","readme":"A powerful, fluent Java wrapper built on top of Apache HTTP Client 5 that simplifies making REST API calls.\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Features](#features)\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Resource Management](#resource-management)\n- [Usage Examples](#usage-examples)\n  - [Creating an HttpRequest](#creating-an-httprequest)\n  - [Making Simple Requests](#making-simple-requests)\n  - [Working with Request Parameters](#working-with-request-parameters)\n  - [Working with Headers](#working-with-headers)\n  - [Handling Responses](#handling-responses)\n  - [Error Handling](#error-handling)\n  - [Working with JSON and XML](#working-with-json-and-xml)\n- [Advanced Features](#advanced-features)\n  - [Connection Pooling](#connection-pooling)\n  - [Timeouts](#timeouts)\n  - [SSL Configuration](#ssl-configuration)\n  - [Authentication](#authentication)\n  - [Redirects](#redirects)\n  - [Retry Mechanism](#retry-mechanism)\n  - [Custom Response Body Readers](#custom-response-body-readers)\n  - [Limiting Response Body Size](#limiting-response-body-size)\n  - [Character Encoding](#character-encoding)\n  - [Debugging](#debugging)\n- [Why use http-request?](#why-use-http-request)\n- [API Documentation](#api-documentation)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Overview\n\nThe http-request library is designed to create a simple REST client quickly, manage responses easily, and handle\nexceptions gracefully. It provides a fluent API that makes HTTP requests more readable and maintainable.\n\nThe main purpose is to simplify the process of making HTTP requests while providing powerful features for handling\nresponses, managing connections, and processing data, building on top of the robust and performant Apache HttpClient 5.\n\n## Features\n\n- **Fluent API**: Build and execute HTTP requests with a clean, chainable API.\n- **Thread-safe**: `HttpRequest` objects are immutable and thread-safe after building.\n- **Simplified Error Handling**: All exceptions are wrapped with meaningful status codes.\n- **Simplified Resource Management**: Automatic closing of responses with `ResponseHandler` and `AutoCloseable` client\n  resources.\n- **Flexible Response Processing**:\n  - Convert responses to Java objects automatically.\n  - Support for JSON and XML deserialization.\n  - Type-safe generic response handling with `TypeReference`.\n- **Connection Management**:\n  - Simplified connection pooling.\n  - Configurable timeouts.\n  - Easy SSL configuration.\n- **Advanced Features**:\n  - Flexible retry mechanism for failed requests.\n  - Custom response body readers and request body converters.\n  - Secure password handling for basic authentication.\n  - Request duration monitoring.\n\n## Requirements\n\n- Java 8 or higher\n- Dependencies (automatically managed by build tools):\n  - Apache HttpClient 5.x\n  - Jackson (for JSON/XML processing)\n  - SLF4J (for logging)\n\n## Installation\n\n### Maven\n\nAdd this dependency to your `pom.xml`:\n\n```xml\n\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.jsunsoft.http\u003c/groupId\u003e\n  \u003cartifactId\u003ehttp-request\u003c/artifactId\u003e\n  \u003cversion\u003e3.5.0-rc2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### Gradle\n\nAdd this dependency to your `build.gradle`:\n\n```groovy\nimplementation 'com.jsunsoft.http:http-request:3.5.0-rc2'\n```\n\n## Quick Start\n\nHere's a simple example to get you started:\n\n```java\nimport com.jsunsoft.http.*;\nimport org.apache.hc.client5.http.impl.classic.CloseableHttpClient;\n\npublic class QuickStart {\n  public static void main(String[] args) {\n    // Create an HTTP client and manage its resources with try-with-resources\n    try (CloseableHttpClient httpClient = ClientBuilder.create().build()) {\n\n      // Build an HTTP request\n      HttpRequest httpRequest = HttpRequestBuilder.create(httpClient).build();\n\n      // Make a GET request and get the response\n      try (Response response = httpRequest.target(\"https://api.example.com/users/1\").get()) {\n        // Check the status code\n        int statusCode = response.getCode();\n        System.out.println(\"Status code: \" + statusCode);\n\n        if (response.isSuccess()) {\n          // Read the response as a string\n          String responseBody = response.readEntity(String.class);\n          System.out.println(\"Response body: \" + responseBody);\n        }\n      }\n    }\n  }\n}\n```\n\n## Resource Management\n\nThis library simplifies resource management to prevent connection leaks.\n\n### Concurrency and Thread Safety\n\n- **HttpRequest**: immutable and thread-safe after building; reuse it across threads.\n- **WebTarget from `target(...)`**: mutable and **not** thread-safe; don't share between threads.\n- **WebTarget from `immutableTarget(...)`**: safe to share and reuse across threads.\n\n### 1. Using `ResponseHandler` (Recommended for most cases)\n\nWhen you use methods that return a `ResponseHandler\u003cT\u003e` (e.g., `get(User.class)`), the response is consumed and closed\nautomatically. This is the most convenient and safest way to handle responses.\n\n```java\n// The response is closed automatically after the operation.\nUser user = httpRequest.target(\"https://api.example.com/users/1\")\n                .get(User.class)\n                .orElseThrow();\n```\n\n### 2. Using `Response` with try-with-resources\n\nWhen you need direct access to the `Response` object, always use a try-with-resources statement to ensure it's closed,\neven if exceptions occur.\n\n```java\ntry(Response response = httpRequest.target(uri).get()){\n    int statusCode = response.getCode();\n    SomeType body = response.readEntity(SomeType.class);\n} // response.close() is called automatically\n```\n\n### 3. Managing the `HttpClient`\n\n`CloseableHttpClient` manages the connection pool and should be shared across your application. It's a heavy-weight\nobject. It's crucial to close it when your application shuts down.\n\n```java\n// Use try-with-resources to manage the client lifecycle\ntry(CloseableHttpClient httpClient = ClientBuilder.create().build()){\n        // ... use the client\n}\n```\n\n## Usage Examples\n\n### Creating an `HttpRequest`\n\nThe `HttpRequestBuilder` is used to create and configure `HttpRequest` instances. `HttpRequest` objects are immutable\nand thread-safe, so you can create one and reuse it.\n\n```java\n// Create a simple HttpRequest\nHttpRequest httpRequest = HttpRequestBuilder.create(httpClient).build();\n\n// Create an HttpRequest with default headers and content type\nHttpRequest httpRequest = HttpRequestBuilder.create(httpClient)\n        .addDefaultHeader(\"User-Agent\", \"MyApp/1.0\")\n        .addContentType(ContentType.APPLICATION_JSON)\n        .build();\n\n// Create an HttpRequest with basic authentication\nHttpRequest httpRequest = HttpRequestBuilder.create(httpClient)\n        .basicAuth(\"username\", \"password\")\n        .build();\n```\n\n### Making Simple Requests\n\nThe library provides convenient methods for all standard HTTP verbs.\n\n- **`get()`**, **`post()`**, **`put()`**, etc., returning a `ResponseHandler\u003cT\u003e` (eager processing): The response is\n  automatically read and converted.\n- **`get()`**, **`post()`**, **`put()`**, etc., returning a `Response` (lazy processing): You have direct control over\n  the response stream.\n\n```java\n// Eager GET: Convert response body to a User object\nResponseHandler\u003cUser\u003e userHandler = httpRequest.target(\"https://api.example.com/users/1\").get(User.class);\nUser user = userHandler.orElseThrow(); // Throws exception if request was not successful\n\n// Eager POST with a JSON payload\nString jsonPayload = \"{\\\"name\\\":\\\"John\\\",\\\"email\\\":\\\"john@example.com\\\"}\";\nResponseHandler\u003cString\u003e postHandler = httpRequest.target(\"https://api.example.com/users\").post(jsonPayload, String.class);\nSystem.out.println(\"Response: \" + postHandler.get());\n\n// Lazy PUT: Get the Response object and handle it manually\ntry(\n    Response putResponse = httpRequest.target(\"https://api.example.com/users/1\").put(jsonPayload)){\n            System.out.println(\"Status code: \" + putResponse.getCode());\n}\n```\n\n### Working with Request Parameters\n\nYou can add query parameters to your requests easily.\n\n```java\n// Add parameters\nResponse response = httpRequest.target(\"https://api.example.com/users\")\n                .addParameter(\"page\", \"1\")\n                .addParameter(\"limit\", \"10\")\n                .get();\n\n// Add multiple parameters from a map\nMap\u003cString, String\u003e params = new HashMap\u003c\u003e();\nparams.put(\"limit\",\"10\");\nparams.put(\"sort\",\"name\");\n\nResponse response = httpRequest.target(\"https://api.example.com/users\")\n        .addParameters(params)\n        .get();\n\n// Add parameters from a query string\nResponse response = httpRequest.target(\"https://api.example.com/users\")\n        .addParameters(\"page=1\u0026limit=10\u0026sort=name\")\n        .get();\n```\n\n### Working with Headers\n\nYou can add headers to individual requests or set default headers on the `HttpRequestBuilder`.\n\n```java\n// Add a header to a single request\nResponse response = httpRequest.target(\"https://api.example.com/users\")\n                .addHeader(\"X-API-Key\", \"your-api-key\")\n                .get();\n\n// Add multiple headers\nResponse response = httpRequest.target(\"https://api.example.com/users\")\n        .addHeader(\"X-API-Key\", \"your-api-key\")\n        .addHeader(\"Accept-Language\", \"en-US\")\n        .get();\n\n// Update or remove headers\nResponse response = httpRequest.target(\"https://api.example.com/users\")\n        .addHeader(\"Accept\", \"application/json\")\n        .updateHeader(\"Accept\", \"application/xml\")\n        .removeHeader(\"X-Temporary\")\n        .get();\n\n// Set a default header for all requests made with this httpRequest instance\nHttpRequest httpRequestWithAuth = HttpRequestBuilder.create(httpClient)\n        .addDefaultHeader(\"Authorization\", \"Bearer your-token\")\n        .build();\n```\n\n### Handling Responses\n\nThe `ResponseHandler` provides a powerful and fluent way to process responses.\n\n```java\nResponseHandler\u003cUser\u003e handler = httpRequest.target(\"https://api.example.com/users/123\").get(User.class);\n\n// Chain success and error handling\nhandler.ifSuccess(h -\u003eSystem.out.println(\"User: \"+h.get().getName()))\n        .otherwise(h -\u003eSystem.err.println(\"Error: \"+h.getErrorText()));\n\n// Using filter and conditional processing\nhandler.filter(ResponseHandler::hasContent).ifPassed(h -\u003eSystem.out.println(\"User: \"+h.get().getName()))\n        .otherwise(h -\u003eSystem.out.println(\"No content\"));\n\n// Get the result or a default value\nUser user = handler.orElse(new User(\"Default\"));\n\n// Get the request duration\nDuration duration = handler.getDuration();\nSystem.out.println(\"Request took: \"+duration.toMillis() +\"ms\");\n\n// Status codes: mapped vs original (ResponseHandler only)\nint code = handler.getCode(); // May be mapped for failures (e.g., 503/502)\nint originalCode = handler.getOriginalCode(); // -1 if no response was received\n```\n\n### Error Handling\n\nThe library wraps exceptions and provides convenient ways to handle errors.\n\n- **Connection failures** → `RequestException` (often with status code 503)\n- **Deserialization failures** → `ResponseBodyProcessingException` (often with status code 502)\n- **Non-2xx status codes** → `UnexpectedStatusCodeException`\n\n```java\ntry{\n// Throws UnexpectedStatusCodeException for non-2xx responses\n// Throws MissingResponseBodyException if the body is empty but required\nUser user = httpRequest.target(\"https://api.example.com/users/999\")\n        .get(User.class)\n        .requiredGet();\n}catch(ResponseException e){\n        System.err.println(\"Response failed: \" + e.getMessage());\n        \n        if(e instanceof UnexpectedStatusCodeException){\n            System.err.println(\"Status code: \" + ((UnexpectedStatusCodeException) e).getStatusCode());\n        }\n}\n```\n\n### Working with JSON and XML\n\nThe library automatically handles JSON and XML serialization/deserialization using Jackson.\n\n```java\n// POST a Java object as JSON\nUser newUser = new User(\"John Doe\", \"john@example.com\");\nResponse response = httpRequest.target(\"https://api.example.com/users\")\n        .post(newUser); // Content-Type is automatically handled for Objects\n\n// GET and parse a generic type (List\u003cUser\u003e)\nList\u003cUser\u003e users = httpRequest.target(\"https://api.example.com/users\")\n        .get(new TypeReference\u003cList\u003cUser\u003e\u003e() {\n        })\n        .orElseThrow();\n\n// Custom date formats for JSON/XML\nHttpRequest httpRequest = HttpRequestBuilder.create(httpClient)\n        .addResponseDefaultDateDeserializationPattern(LocalDate.class, \"yyyy-MM-dd\")\n        .addResponseDefaultDateDeserializationPattern(LocalDateTime.class, \"yyyy-MM-dd HH:mm:ss\")\n        .addRequestDefaultDateSerializationPattern(LocalDateTime.class, \"yyyy-MM-dd'T'HH:mm:ss\")\n        .build();\n```\n\n## Advanced Features\n\n### Connection Pooling\n\nConfigure the connection pool using `ClientBuilder`.\n\n```java\nCloseableHttpClient httpClient = ClientBuilder.create()\n        .setMaxPoolSize(200) // Total connections\n        .setDefaultMaxPoolSizePerRoute(50) // Connections per host\n        .setMaxPoolSizePerRoute(\"api.example.com\", 100) // Specific host\n        .build();\n```\n\nBy default, Apache HttpClient uses small pool limits (for example, 2 per route). When you use `ClientBuilder`, the\ndefaults are set to 128 for max total and max per route. Override them based on your traffic patterns.\n\nYou can also configure a proxy:\n\n```java\nCloseableHttpClient httpClient = ClientBuilder.create()\n        .proxy(\"proxy.mycorp.local\", 8080)\n        .build();\n```\n\nOr customize the underlying `HttpClientBuilder`:\n\n```java\nCloseableHttpClient httpClient = ClientBuilder.create()\n        .addHttpClientCustomizer(builder -\u003e\n                builder.setKeepAliveStrategy((response, context) -\u003e /* your strategy */ 30_000))\n        .build();\n```\n\n### Timeouts\n\nConfigure various timeouts for your HTTP client.\n\n```java\nCloseableHttpClient httpClient = ClientBuilder.create()\n        .setConnectTimeout(5000)               // Connection timeout in ms\n        .setResponseTimeout(30000)             // Response timeout in ms\n        .setConnectionRequestTimeout(30000)    // Time to wait for a pooled connection\n        .setSocketTimeout(30000)               // Socket timeout in ms\n        .build();\n```\n\nDefault timeouts used by `ClientBuilder`:\n\n- Response timeout: 30000ms\n- Connection request timeout: 30000ms\n- Connect timeout: 10000ms\n- Socket timeout: 30000ms\n\nTimeouts can be overridden per request:\n\n```java\nHttpRequest httpRequest = HttpRequestBuilder.create(httpClient).build();\n\nhttpRequest.target(uri)\n        .setRequestConfig(customRequestConfig)\n        .get();\n```\n\n### SSL Configuration\n\nEasily configure SSL settings.\n\n```java\n// Trust all certificates (INSECURE: for testing only)\nCloseableHttpClient httpClient = ClientBuilder.create()\n                .trustAllCertificates()\n                .trustAllHosts()\n                .build();\n```\n\n### Authentication\n\nThe library supports basic authentication securely.\n\n```java\n// Securely provide password as a char array (will be cleared after use)\nHttpRequest httpRequest = HttpRequestBuilder.create(httpClient)\n                .basicAuth(\"user\", new char[]{'s', 'e', 'c', 'r', 'e', 't'})\n                .build();\n```\n\n### Redirects\n\nConfigure how redirects are handled. By default, they are disabled.\n\n```java\n// Enable a standard redirect strategy\nCloseableHttpClient httpClient = ClientBuilder.create()\n                .enableDefaultRedirectStrategy()\n                .build();\n\n// Enable lax redirect strategy\nCloseableHttpClient httpClient = ClientBuilder.create()\n        .enableLaxRedirectStrategy()\n        .build();\n\n// Set a custom redirect strategy\nCloseableHttpClient httpClient = ClientBuilder.create()\n        .setRedirectStrategy(customRedirectStrategy)\n        .build();\n```\n\n### Retry Mechanism\n\nThe library offers two ways to handle retries:\n\n#### 1. `RetryableWebTarget` (Recommended)\n\nThis provides fine-grained control over retry logic.\n\n```java\n// Retry 3 times with a 2-second delay if the status is 503\nRetryContext retryContext = new RetryContext(3, 2000, response -\u003e response.getCode() == 503);\n\nResponse response = httpRequest.retryableTarget(\"https://api.example.com/status/503\", retryContext)\n        .get();\n```\n\n#### 2. Apache HttpClient's Automatic Retries\n\nEnable the default, less flexible retry mechanism from the underlying client.\n\n```java\nCloseableHttpClient httpClient = ClientBuilder.create()\n        .enableAutomaticRetries()\n        .build();\n```\n\n### Custom Response Body Readers\n\nCreate custom readers for special response formats.\n\n```java\nHttpRequest httpRequest = HttpRequestBuilder.create(httpClient)\n        .addBodyReader(new MyCustomReader())\n        .build();\n```\n\nYou can also implement a `ResponseBodyReader` directly and (optionally) disable default readers:\n\n```java\nHttpRequest httpRequest = HttpRequestBuilder.create(closeableHttpClient)\n        // .disableDefaultBodyReader() // Disable defaults if needed\n        .addBodyReader(new ResponseBodyReader\u003cMap\u003cString, String\u003e\u003e() {\n            @Override\n            public boolean isReadable(ResponseBodyReadableContext ctx) {\n                return ctx.getType() == Map.class;\n            }\n\n            @Override\n            public ResponseData read(ResponseBodyReaderContext\u003cMap\u003cString, String\u003e\u003e ctx)\n                    throws IOException, ResponseBodyReaderException {\n                return new ObjectMapper()\n                        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)\n                        .readValue(ctx.getContent(), ctx.getGenericType());\n            }\n        })\n        .build();\n```\n\n### Limiting Response Body Size\n\nTo protect your application from OutOfMemoryErrors caused by unexpectedly large HTTP responses, you can set a maximum\nsize for the response body. This feature is now consistently applied to all response types (String, JSON/XML objects,\netc.).\n\nBy default, the response body size is **unlimited**. You can configure a limit on the `HttpRequestBuilder`.\n\nThe limit is enforced by wrapping the response entity as soon as the response is received. If the response size exceeds\nthis limit during reading, an `InvalidContentLengthException` is thrown. This exception is then wrapped and propagated\nto you.\n\n- When using a `ResponseHandler`, methods like `.orElseThrow()` will throw a `ResponseException`. The cause of this\n  exception will be the `InvalidContentLengthException`.\n\n**Important:** Even when this limit is exceeded, the underlying HTTP connection is **always safely closed and released\nback to the pool**. The library ensures resources are cleaned up correctly to prevent connection leaks.\n\n```java\n// Configure a client with a 1KB limit\nHttpRequest httpRequest = HttpRequestBuilder.create(httpClient)\n                .setMaxResponseBodySizeBytes(1024)\n                .build();\n\n// This endpoint returns a 2KB response\nserver.stubFor(get(urlEqualTo(\"/large-response\"))\n        .willReturn(aResponse().withStatus(200).withBody(\"a\".repeat(2048))));\n\ntry{\n    httpRequest.target(httpUri(\"/large-response\"))\n        .get(String.class)\n        .orElseThrow();\n\n}catch(ResponseException e){\n        System.out.println(\"Correctly caught expected exception: \"+e.getClass().getName());\n\n        // Check the cause to see if it was due to the size limit\n        if(e.getCause() instanceof InvalidContentLengthException){\n            System.out.println(\"Cause was InvalidContentLengthException, as expected.\");\n        // Handle the error appropriately\n        }\n}\n```\n\n\u003e **A Note on Connection Handling:** The library's closing behavior changes depending on whether a size limit is set.\n\u003e - **Without a size limit:** The library attempts to fully consume the response body before closing. This is a\n    performance optimization that allows the underlying connection to be kept alive and reused for subsequent requests\n    to the same host.\n\u003e - **With a size limit:** The library **intentionally does not** consume the rest of the body. It immediately closes\n    the connection to avoid downloading potentially huge amounts of unwanted data. While this may prevent the connection\n    from being reused, it guarantees safety and responsiveness, and the connection is always correctly returned to the\n    pool.\n\n### Character Encoding\n\nSpecify charsets for URI paths/queries and for request bodies.\n\n```java\nhttpRequest.target(\"https://api.example.com/search\")\n    .setUriCharset(StandardCharsets.UTF_8) // For query params\n    .setBodyCharset(StandardCharsets.ISO_8859_1) // For request body\n    .addParameter(\"q\",\"你好\")\n    .post(\"some-body\");\n```\n\n### Debugging\n\nEnable request payload logging for easier debugging.\n\n```java\nHttpRequest httpRequest = HttpRequestBuilder.create(httpClient)\n        .enableRequestPayloadLogging()\n        .build();\n```\n\n## Why use http-request?\n\nWhile Apache HttpClient is a powerful and flexible library, `http-request` provides a higher-level, fluent API that\nmakes common tasks simpler, safer, and more readable.\n\n| Feature                  | Pure Apache HttpClient 5                                          | `http-request` Library                                                                             |\n|--------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------|\n| **Request Creation**     | Manually create `ClassicRequestBuilder`, set URI, method, entity. | Fluent, chainable API: `httpRequest.target(uri).get()`.                                            |\n| **JSON/XML Handling**    | Manually use `ObjectMapper` to serialize/deserialize entities.    | Automatic conversion: `post(userObject)`, `get(User.class)`.                                       |\n| **Resource Management**  | Manually close `CloseableHttpResponse` and `CloseableHttpClient`. | Automatic with `ResponseHandler` or simple with `try-with-resources`.                              |\n| **Error Handling**       | Check status codes manually, handle `IOException`s.               | Fluent `ifSuccess().otherwise()` chains, specific exceptions like `UnexpectedStatusCodeException`. |\n| **Configuration**        | Verbose builders for client, request config, connection manager.  | Simplified `ClientBuilder` and `HttpRequestBuilder` for common settings.                           |\n| **Generics (`List\u003cT\u003e`)** | Manually handle `TypeReference` with `ObjectMapper`.              | Built-in support: `get(new TypeReference\u003cList\u003cUser\u003e\u003e() {})`.                                       |\n| **Retry Logic**          | Implement a custom `HttpRequestRetryStrategy`.                    | Simple and powerful `RetryableWebTarget` with `RetryContext`.                                      |\n| **Readability**          | Can become verbose and procedural.                                | Clean, declarative, and easy to read.                                                              |\n\nIn short, `http-request` accelerates development, reduces boilerplate, and helps you write more maintainable and robust\nHTTP client code.\n\n## API Documentation\n\nFull API documentation is available [here](http://javadoc.io/doc/com.jsunsoft.http/http-request).\n\nAdditional documentation:\n\n- [Release Changes](CHANGES.md)\n- [Migration Guide](MIGRATION.md)\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.\n\n---\n\nSupported by [JetBrains](https://www.jetbrains.com/?from=http-request)","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjsunsoftware%2Fhttp-request","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjsunsoftware%2Fhttp-request","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjsunsoftware%2Fhttp-request/lists"}