{"id":45466415,"url":"https://github.com/sashirestela/cleverclient","last_synced_at":"2026-02-22T09:49:36.390Z","repository":{"id":197107818,"uuid":"694861119","full_name":"sashirestela/cleverclient","owner":"sashirestela","description":"A Java library for making http client and websocket requests easily.","archived":false,"fork":false,"pushed_at":"2025-07-04T21:26:31.000Z","size":635,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-04T22:28:29.091Z","etag":null,"topics":["api-rest","client","http","httpclient","java","okhttp","okhttpclient","rest","restclient","websocket","websocket-client"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sashirestela.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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}},"created_at":"2023-09-21T21:08:52.000Z","updated_at":"2025-07-04T21:14:26.000Z","dependencies_parsed_at":"2023-09-29T01:58:38.517Z","dependency_job_id":"5e747dcf-7ac5-4424-bb60-35fc244164db","html_url":"https://github.com/sashirestela/cleverclient","commit_stats":{"total_commits":71,"total_committers":3,"mean_commits":"23.666666666666668","dds":"0.15492957746478875","last_synced_commit":"b562c01ff6dfd9599d133fe5a2b1f9c002fd0791"},"previous_names":["sashirestela/cleverclient"],"tags_count":44,"template":false,"template_full_name":null,"purl":"pkg:github/sashirestela/cleverclient","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sashirestela%2Fcleverclient","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sashirestela%2Fcleverclient/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sashirestela%2Fcleverclient/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sashirestela%2Fcleverclient/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sashirestela","download_url":"https://codeload.github.com/sashirestela/cleverclient/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sashirestela%2Fcleverclient/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29708374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T05:59:28.568Z","status":"ssl_error","status_checked_at":"2026-02-22T05:58:46.208Z","response_time":110,"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":["api-rest","client","http","httpclient","java","okhttp","okhttpclient","rest","restclient","websocket","websocket-client"],"created_at":"2026-02-22T09:49:35.673Z","updated_at":"2026-02-22T09:49:36.381Z","avatar_url":"https://github.com/sashirestela.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 💎 CleverClient\n\nA Java library for making http client and websocket requests easily.\n\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=sashirestela_cleverclient\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=sashirestela_cleverclient)\n[![codecov](https://codecov.io/gh/sashirestela/cleverclient/graph/badge.svg?token=PEYAFW3EWD)](https://codecov.io/gh/sashirestela/cleverclient)\n![Maven Central](https://img.shields.io/maven-central/v/io.github.sashirestela/cleverclient)\n![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/sashirestela/cleverclient/build_java_maven.yml)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/sashirestela/cleverclient)\n\n### Table of Contents\n- [Description](#-description)\n- [How to Use](#-how-to-use)\n- [Installation](#-installation)\n- [Features](#-features)\n  - [CleverClient Creation](#cleverclient-creation)\n  - [Interface Annotations](#interface-annotations)\n  - [Supported Response Types](#supported-response-types)\n  - [Interface Default Methods](#interface-default-methods)\n  - [Exception Handling](#exception-handling)\n  - [Retries](#retries)\n  - [WebSocket](#websocket)\n- [Examples](#-examples)\n- [Contributing](#-contributing)\n- [License](#-license)\n- [Show Us Your Love](#-show-us-your-love)\n\n## 💡 Description\n\nCleverClient is a Java library that simplifies requesting client-side Http services and websockets using annotated interfaces and methods. CleverClient uses behind the scenes two out-of-box Http client libraries: [Java's HttpClient](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html) (by default) or [Square's OkHttp](https://square.github.io/okhttp/) (adding a dependency).\n\n## 📘 How to Use\n\nFor example, if we want to use the public API [JsonPlaceHolder](https://jsonplaceholder.typicode.com/) and call its endpoint ```/posts```, we just have to create an entity ```Post```, an interface ```PostService``` with special annotatons, and call the API through ```CleverClient```:\n\n```java\n// Entity\npublic class Post {\n  private Integer id;\n  private String title;\n  private String body;\n  private Integer userId;\n\n  // Constructors , getters, setters, etc.\n}\n\n// Interface\n@Resource(\"/posts\")\npublic interface PostService {\n\n  @GET\n  List\u003cPost\u003e readPosts(@Query(\"_page\") Integer page, @Query(\"_limit\") Integer limit);\n\n  @GET(\"/{postId}\")\n  Post readPost(@Path(\"postId\") Integer postId);\n\n  @POST\n  Post createPost(@Body Post post);\n\n}\n\n// Use CleverClient to call the API\nvar cleverClient = CleverClient.builder()\n    .baseUrl(\"https://jsonplaceholder.typicode.com\")\n    .build();\n\nvar postService = cleverClient.create(PostService.class);\n\nvar page = 1;\nvar limit = 5;\nvar postId = 17;\nvar userId = 3;\n\n// Example Read Posts\nvar postsList = postService.readPosts(page, limit);\npostsList.forEach(System.out::println);\n\n// Example Read Post\nvar onePost = postService.readPost(postId);\nSystem.out.println(onePost);\n\n// Example Create Post\nvar newPost = postService.createPost(new Post(\n    null,\n    \"Hello\",\n    \"Hello word, you are very welcome!\",\n    userId));\nSystem.out.println(newPost);\n```\n\n## ⚙ Installation\n\nYou can install CleverClient by adding the following dependencies to your Maven project:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.sashirestela\u003c/groupId\u003e\n    \u003cartifactId\u003ecleverclient\u003c/artifactId\u003e\n    \u003cversion\u003e[cleverclient_latest_version]\u003c/version\u003e\n\u003c/dependency\u003e\n\u003c!-- OkHttp dependency is optional if you decide to use it with CleverClient --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.squareup.okhttp3\u003c/groupId\u003e\n    \u003cartifactId\u003eokhttp\u003c/artifactId\u003e\n    \u003cversion\u003e[okhttp_latest_version]\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nOr alternatively using Gradle:\n\n```groovy\ndependencies {\n    implementation(\"io.github.sashirestela:cleverclient:[cleverclient_latest_version]\")\n    /* OkHttp dependency is optional if you decide to use it with CleverClient */\n    implementation(\"com.squareup.okhttp3:okhttp:[okhttp_latest_version]\")\n}\n```\n\nTake in account that you need to use **Java 11 or greater**.\n\n## 📕 Features\n\n### CleverClient Creation\n\nWe have the following attributes to create a CleverClient object:\n\n| Attribute          | Description                                                  | Required  |\n| -------------------|--------------------------------------------------------------|-----------|\n| baseUrl            | Api's url                                                    | mandatory |\n| headers            | Map of headers (name/value)                                  | optional  |\n| header             | Single header as a name and a value                          | optional  |\n| bodyInspector      | Function to inspect the `@Body` request parameter            | optional  |\n| requestInterceptor | Function to modify the request once is built                 | optional  |\n| responseInterceptor| Function to modify the response after it's received          | optional  |\n| retryConfig        | Configuration for retrying failed requests                   | optional  |\n| clientAdapter      | Http client implementation (Java HttpClient or OkHttp based) | optional  |\n| endsOfStream       | List of texts used to mark the end of streams                | optional  |\n| endOfStream        | Text used to mark the end of streams                         | optional  |\n| objectMapper       | Provides Json conversions either to/from objects             | optional  |\n\n```end(s)OfStream``` is required when you have endpoints sending back streams of data (Server Sent Events - SSE).\n\nThe attribute ```clientAdapter``` determines which Http client implementation to use. CleverClient supports two implementations out of the box:\n- Java's HttpClient (default) via ```JavaHttpClientAdapter```\n- Square's OkHttp via ```OkHttpClientAdapter```\n\n| clientAdapter's value                           | Description                         |\n|-------------------------------------------------|-------------------------------------|\n| new JavaHttpClientAdapter()                     | Uses a default Java's HttpClient    |\n| new JavaHttpClientAdapter(customJavaHttpClient) | Uses a custom Java's HttpClient     |\n| new OkHttpClientAdapter()                       | Uses a default OkHttpClient         |\n| new OkHttpClientAdapter(customOkHttpClient)     | Uses a custom OkHttpClient          |\n\nExample:\n\n```java\nfinal var BASE_URL = \"https://api.example.com\";\nfinal var HEADER_NAME = \"Authorization\";\nfinal var HEADER_VALUE = \"Bearer qwertyasdfghzxcvb\";\nfinal var END_OF_STREAM = \"[DONE]\";\n\nvar httpClient = HttpClient.newBuilder()\n    .version(Version.HTTP_1_1)\n    .followRedirects(Redirect.NORMAL)\n    .connectTimeout(Duration.ofSeconds(20))\n    .executor(Executors.newFixedThreadPool(3))\n    .proxy(ProxySelector.of(new InetSocketAddress(\"proxy.example.com\", 80)))\n    .build();\n\nvar objectMapper = new ObjectMapper()\n    .registerModule(new JavaTimeModule());\n\nvar cleverClient = CleverClient.builder()\n    .baseUrl(BASE_URL)\n    .header(HEADER_NAME, HEADER_VALUE)\n    .bodyInspector(body -\u003e {\n        var validator = new Validator();\n        var violations = validator.validate(body);\n        if (!violations.isEmpty()) {\n            throw new ConstraintViolationException(violations);\n        }\n    })\n    .requestInterceptor(request -\u003e {\n        var url = request.getUrl();\n        url + (url.contains(\"?\") ? \"\u0026\" : \"?\") + \"env=testing\";\n        request.setUrl(url);\n        return request;\n    })\n    .responseInterceptor(response -\u003e {\n        var modifiedBody = customProcessing(response.getBody());\n        response.setBody(modifiedBody);\n        return response;\n    })\n    .retryConfig(RetryConfig.defaultValues())  // Using the default values for retrying\n    .clientAdapter(new JavaHttpClientAdapter(httpClient))\n    .endOfStream(END_OF_STREAM)\n    .objectMapper(objectMapper)\n    .build();\n```\n\n### Interface Annotations\n\n| Annotation | Target     | Attributes                  | Required Attrs | Mult |\n|------------|------------|-----------------------------|----------------|------|\n| Resource   | Interface  | Resource's url              | optional       | One  |\n| Header     | Interface  | Header's name and value     | mandatory both | Many |\n| Header     | Method     | Header's name and value     | mandatory both | Many |\n| GET        | Method     | GET endpoint's url          | optional       | One  |\n| POST       | Method     | POST endpoint's url         | optional       | One  |\n| PUT        | Method     | PUT endpoint's url          | optional       | One  |\n| DELETE     | Method     | DELETE endpoint's url       | optional       | One  |\n| PATCH      | Method     | PATCH endpoint's url        | optional       | One  |\n| Multipart  | Method     | (None)                      | none           | One  |\n| StreamType | Method     | Class type and events array | mandatory both | Many |\n| StreamType | Annotation | Class type and events array | mandatory both | Many |\n| Path       | Parameter  | Path parameter name in url  | mandatory      | One  |\n| Query      | Parameter  | Query parameter name in url | mandatory      | One  |\n| Query      | Parameter  | (None for Pojos)            | none           | One  |\n| Body       | Parameter  | (None)                      | none           | One  |\n\n* ```Resource``` could be used to separate the repeated part of the endpoints' url in an interface.\n* ```Header``` Used to include more headers (pairs of name and value) at interface or method level. It is possible to have multiple Header annotations for the same target.\n* ```GET, POST, PUT, DELETE, PATCH``` are used to mark the typical http methods (endpoints).\n* ```Multipart``` is used to mark an endpoint with a multipart/form-data request. This is required when you need to upload files.\n* ```StreamType``` is used with methods whose return type is Stream of [Event](./src/main/java/io/github/sashirestela/cleverclient/Event.java). Tipically you will use more than one of this annotation to indicate what classes (types) are related to what events (array of Strings). You can also use them for custom annotations in case you want to reuse them for many methods, so you just apply the custom composite annotation.\n* ```Path``` is used to replace the path parameter name in url with the matched method parameter's value.\n* ```Query``` is used to add a query parameter to the url in the way: [?]queryValue=parameterValue[\u0026...] for scalar parameters. Also it can be used for POJOs using its properties and values. For array and collection values it'll be expanded as: queryValue=paramValue1\u0026queryValue=paramValue2\u0026...\u0026queryValue=paramValueN.\n* ```Body``` is used to mark a method parameter as the endpoint's payload request, so the request will be application/json at least the endpoint is annotated with Multipart.\n* Check the above [Description's example](#-description) or the [Test](https://github.com/sashirestela/cleverclient/tree/main/src/test/java/io/github/sashirestela/cleverclient) folder to see more of these interface annotations in action.\n\n### Supported Response Types\n\nThe reponse types are determined from the method's return types. We have six response types: [Stream](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Stream.html) of elements, [List](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html) of elements, [Generic](https://docs.oracle.com/javase/tutorial/java/generics/types.html) type, Custom type, [Binary](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/InputStream.html) type, [String](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/String.html) type and Stream of [Event](./src/main/java/io/github/sashirestela/cleverclient/Event.java), and all of them can be asynchronous or synchronous. For async responses you have to use the Java class [CompletableFuture](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CompletableFuture.html).\n\n| Response Type                      | Sync/Async | Description                 |\n|------------------------------------|------------|-----------------------------|\n| CompletableFuture\u003cStream\\\u003cT\u003e\u003e      | Async      | SSE (*) as Stream of type T |\n| Stream\\\u003cT\u003e                         | Sync       | SSE (*) as Stream of type T |\n| CompletableFuture\u003cList\\\u003cT\u003e\u003e        | Async      | List of type T              |\n| List\\\u003cT\u003e                           | Sync       | List of type T              |\n| CompletableFuture\u003cGeneric\\\u003cT\u003e\u003e     | Async      | Generic class of type T     |\n| Generic\\\u003cT\u003e                        | Sync       | Generic class of type T     |\n| CompletableFuture\\\u003cT\u003e              | Async      | Custom class T              |\n| T                                  | Sync       | Custom class T              |\n| CompletableFuture\\\u003cInputStream\u003e    | Async      | Binary type                 |\n| InputStream                        | Sync       | Binary type                 |\n| CompletableFuture\\\u003cString\u003e         | Async      | String type                 |\n| String                             | Sync       | String type                 |\n| CompletableFuture\u003cStream\\\u003cEvent\u003e\u003e  | Async      | SSE (*) as Stream of Event  |\n| Stream\\\u003cEvent\u003e                     | Sync       | SSE (*) as Stream of Event  |\n\n(*) SSE: Server Sent Events\n\n* ```CompletableFuture\u003cStream\u003cT\u003e\u003e``` and ```Stream\u003cT\u003e``` are used for handling SSE without events and data of the class ```T``` only.\n* ```CompletableFuture\u003cStream\u003cEvent\u003e\u003e``` and ```Stream\u003cEvent\u003e``` are used for handling SSE with multiple events and data of different classes.\n* The [Event](./src/main/java/io/github/sashirestela/cleverclient/Event.java) class will bring for each event: the event name and the data object.\n\n### Interface Default Methods\n\nYou can create interface default methods to execute special requirements such as pre/post processing before/after calling annotated regular methods. For example in the following interface definition, we have two regular methods with POST annotation which are called from another two default methods. In those defaults methods we are making some pre processing (in this case, modifying the request object) before calling the annotated methods:\n\n```java\n@Resource(\"/v1/chat/completions\")\ninterface Completions {\n\n    @POST\n    Stream\u003cChatResponse\u003e createSyncStreamBasic(@Body ChatRequest chatRequest);\n\n    @POST\n    CompletableFuture\u003cStream\u003cChatResponse\u003e\u003e createAsyncStreamBasic(@Body ChatRequest chatRequest);\n\n    default Stream\u003cChatResponse\u003e createSyncStream(ChatRequest chatRequest) {\n        var request = chatRequest.withStream(true);\n        return createSyncStreamBasic(request);\n    }\n\n    default CompletableFuture\u003cStream\u003cChatResponse\u003e\u003e createAsyncStream(ChatRequest chatRequest) {\n        var request = chatRequest.withStream(true);\n        return createAsyncStreamBasic(request);\n    }\n\n}\n```\nNote that we have named the annotated methods with the suffix \"Basic\" just to indicate that we should not call them directly but should call the default ones (those without the suffix).\n\n### Exception Handling\n\nCleverClient provides a flexible exception handling mechanism through the `ExceptionConverter` abstract class. This allows you to convert HTTP errors and other exceptions into your own custom exceptions. Here's how to use it:\n\n1. Create your custom HTTP exception class.\n2. Create your exception converter by extending `ExceptionConverter`.\n3. Implement the `convertHttpException` method to handle HTTP errors.\n\nBasic example:\n\n```java\n// Custom HTTP Exceptions\npublic class FirstHttpException extends RuntimeException {\n    private final String errorDetail;\n\n    public FirstHttpException(String errorDetail) {\n        this.errorDetail = errorDetail;\n    }\n    \n    // Getters\n}\n\npublic class SecondHttpException extends RuntimeException {\n    private final String errorDetail;\n\n    public SecondHttpException(String errorDetail) {\n        this.errorDetail = errorDetail;\n    }\n    \n    // Getters\n}\n\n// Custom Exception Converter\npublic class MyExceptionConverter extends ExceptionConverter {\n    public static void rethrow(Throwable e) {\n        throw new MyExceptionConverter().convert(e);\n    }\n\n    @Override\n    public RuntimeException convertHttpException(ResponseInfo responseInfo) {\n        if (responseInfo.getStatusCode() == 400) {\n            return new FirstHttpException(responseInfo.getData());\n        } else if (responseInfo.getStatusCode() == 401) {\n            return new SecondHttpException(responseInfo.getData());\n        }\n    }\n}\n\n// Usage in try-catch block\ntry {\n    // Your CleverClient API calls here\n} catch (Exception e) {\n    try {\n        MyExceptionConverter.rethrow(e);\n    } catch (FirstHttpException fhe) {\n        // Handle your first custom exception\n    } catch (SecondHttpException she) {\n        // Handle your second custom exception\n\n    // ... Other custom exceptions\n\n    } catch (RuntimeException re) {\n        // Handle default exceptions\n    }\n}\n```\nThis mechanism allows you to handle both HTTP errors and other runtime exceptions in a clean, consistent way while preserving the original error information from the API response.\n\n### Retries\n\nCleverClient provides automatic request retries using exponential backoff with optional jitter. You can configure retries using the `RetryConfig` class.\n\n#### Retry Configuration Options\n\n| Attribute            | Description                                           | Default Value |\n|----------------------|-------------------------------------------------------|---------------|\n| maxAttempts          | Maximum number of retry attempts                      | 3             |\n| initialDelayMs       | Initial delay before retrying (in milliseconds)       | 1000          |\n| maxDelayMs           | Maximum delay between retries (in milliseconds)       | 10000         |\n| backoffMultiplier    | Multiplier for exponential backoff                    | 2.0           |\n| jitterFactor         | Percentage of jitter to apply to delay values         | 0.2           |\n| retryableExceptions  | List of exception types that should trigger a retry   | IOException, ConnectException, SocketTimeoutException |\n| retryableStatusCodes | List of HTTP status codes that should trigger a retry | 408, 409, 429, 500-599 |\n\n#### Example Usage\n\n```java\nvar retryConfig = RetryConfig.builder()\n    .maxAttempts(4)\n    .initialDelayMs(500)\n    .maxDelayMs(8000)\n    .backoffMultiplier(1.5)\n    .jitterFactor(0.1)\n    .retryableExceptions(IOException.class, SocketTimeoutException.class)\n    .retryableStatusCodes(new int[][] { { 429 }, { 500, 503 } })\n    .build();\n\nvar cleverClient = CleverClient.builder()\n    .baseUrl(\"https://api.example.com\")\n    .retryConfig(retryConfig)\n    .build();\n```\n\nWith this configuration, failed requests matching the criteria will be retried automatically with increasing delays based on exponential backoff.\n\n### WebSocket\n\nWe have the following attributes to create a CleverClient.WebSocket object:\n\n| Attribute          | Description                                                  | Required  |\n| -------------------|--------------------------------------------------------------|-----------|\n| baseUrl            | WebSocket's url                                              | mandatory |\n| queryParams        | Map of query params (name/value)                             | optional  |\n| queryParam         | Single query param as a name and a value                     | optional  |\n| headers            | Map of headers (name/value)                                  | optional  |\n| header             | Single header as a name and a value                          | optional  |\n| webSocketAdapter   | WebSocket implementation (Java HttpClient or OkHttp based)   | optional  |\n\nThe attribute ```webSocketAdapter``` lets you specify which WebSocket implementation to use. You can choose between:\n- Java's HttpClient (default) via ```JavaHttpWebSocketAdapter```\n- Square's OkHttp via ```OkHttpWebSocketAdapter```\n\n| webSocketAdapter's value                           | Description                         |\n|----------------------------------------------------|-------------------------------------|\n| new JavaHttpWebSocketAdapter()                     | Uses a default Java's HttpClient    |\n| new JavaHttpWebSocketAdapter(customJavaHttpClient) | Uses a custom Java's HttpClient     |\n| new OkHttpWebSocketAdapter()                       | Uses a default OkHttpClient         |\n| new OkHttpWebSocketAdapter(customOkHttpClient)     | Uses a custom OkHttpClient          |\n\nExample:\n\n```java\nfinal var BASE_URL = \"ws://websocket.example.com\";\nfinal var HEADER_NAME = \"Authorization\";\nfinal var HEADER_VALUE = \"Bearer qwertyasdfghzxcvb\";\n\nvar httpClient = HttpClient.newBuilder()\n    .version(Version.HTTP_1_1)\n    .followRedirects(Redirect.NORMAL)\n    .connectTimeout(Duration.ofSeconds(20))\n    .executor(Executors.newFixedThreadPool(3))\n    .proxy(ProxySelector.of(new InetSocketAddress(\"proxy.example.com\", 80)))\n    .build();\n\nvar webSocket = CleverClient.WebSocket.builder()\n    .baseUrl(BASE_URL)\n    .queryParam(\"model\", \"qwerty_model\")\n    .header(HEADER_NAME, HEADER_VALUE)\n    .webSocketAdapter(new JavaHttpWebSocketAdapter(httpClient))\n    .build();\n\nwebSocket.onOpen(() -\u003e System.out.println(\"Connected\"));\nwebSocket.onMessage(message -\u003e System.out.println(\"Received: \" + message));\nwebSocket.onClose((code, message) -\u003e System.out.println(\"Closed\"));\n\nwebSocket.connect().join();\nwebSocket.send(\"Hello World!\").join();\nwebSocket.send(\"Welcome to the Jungle!\").join();\nwebSocket.close();\n```\n\n\n## ✳ Examples\n\nSome examples have been created in the folder [example](https://github.com/sashirestela/cleverclient/tree/main/src/example/java/io/github/sashirestela/cleverclient/example) and you can follow the next steps to execute them:\n\n* Clone this respository:\n\n  ```sh\n  git clone https://github.com/sashirestela/cleverclient.git\n  cd cleverclient\n  ```\n\n* Build the project:\n\n  ```sh\n  mvn clean install\n  ```\n\n* Run example:\n\n  ```sh\n  mvn -q exec:java -Dexec.mainClass=io.github.sashirestela.cleverclient.example.\u003cclassName\u003e\n  ```\n\n  Where:\n\n  * ```\u003cclassName\u003e``` is mandatory and must be one of the Java files in the folder example: BasicExample, BasicExampleOkHttp, StreamExample, StreamExampleOkHttp, etc.\n  \n    Some examples require you have an OpenAI account and set the env variable OPENAI_API_TOKEN, such as Multipart*, Stream*.\n  \n  * For example, to run the BasicExample:\n    * ```mvn -q exec:java -Dexec.mainClass=io.github.sashirestela.cleverclient.example.BasicExample```\n\n## 💼 Contributing\nPlease read our [Contributing](CONTRIBUTING.md) guide to learn and understand how to contribute to this project.\n\n## 📄 License\nCleverClient is licensed under the MIT License. See the\n[LICENSE](https://github.com/sashirestela/cleverclient/blob/main/LICENSE) file\nfor more information.\n\n## ❤ Show Us Your Love\nThanks for using **cleverclient**. If you find this project valuable there are a few ways you can show us your love, preferably all of them 🙂:\n\n* Letting your friends know about this project 🗣📢.\n* Writing a brief review on your social networks ✍🌐.\n* Giving us a star on Github ⭐.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsashirestela%2Fcleverclient","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsashirestela%2Fcleverclient","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsashirestela%2Fcleverclient/lists"}