Concept
Sinobu provides a concise and powerful API for making HTTP(S) requests and handling
WebSocket connections, built on top of Java's standard HttpClient
.
It simplifies common tasks like handling responses, content negotiation,
and asynchronous processing using Signal
.
💡 Fluent API
Simple static methods in I
enable common HTTP GET requests and WebSocket
connections without boilerplate.
🔧 Standard Integration
Built on java.net.http.HttpRequest.Builder
, allowing fine-grained control over
headers, methods, and request bodies.
🔄 Automatic Content Handling
Response bodies are automatically converted to suitable types (String, JSON, XML, beans, etc.), with gzip/deflate decompression handled transparently.
⚙️ Reactive Streams
Both HTTP and WebSocket messages are streamed asynchronously via Signal
,
promoting non-blocking and reactive design.
🔌 WebSocket Support
Provides a simple API for establishing WebSocket connections and handling incoming/outgoing messages with ease.
Request and Response
Making HTTP requests and processing responses is streamlined using I#http
methods.
You can make simple GET requests with just a URL or use Java's
java.net.http.HttpRequest.Builder
for full control over the request details (method, headers, body, etc.).
Responses are delivered asynchronously as a Signal
.
// Simple GET request, response as String
I.http("https://example.com/data", String.class).to(html -> {
System.out.println("Fetched HTML: " + html.substring(0, 100) + "...");
});
// POST request with custom headers, response mapped to a User object
HttpRequest.Builder request = HttpRequest.newBuilder(URI.create("https://api.example.com/users"))
.POST(HttpRequest.BodyPublishers.ofString("{\"name\":\"John\"}"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer your_token");
I.http(request, User.class).to(user -> {
System.out.println("Created user: " + user.getName());
});
// Synchronous execution (blocks until response or error)
try {
String result = I.http("https://example.com", String.class).waitForTerminate().to().exact();
System.out.println("Synchronous result: " + result);
} catch (Exception e) {
System.err.println("Request failed: " + e);
}
Errors during the request (network issues, HTTP status codes >= 400) are propagated
through the I#signalError(Throwable)
channel.
Supported Type
The I#http
methods automatically convert the response body to the specified Java
type.
This simplifies handling different content types.
Supported types include:
String
: The response body is read as a UTF-8 string.InputStream
: Provides direct access to the (potentially decompressed) response body stream. You are responsible for closing this stream.HttpResponse
: Provides the full `HttpResponse` object, giving access to status code, headers, and the body stream. XML
: Parses the response body as XML/HTML into anXML
object.- JSON: Parses the response body as JSON into a JSON object.
- Any JSON-mappable Bean/Record: Parses the JSON response body and maps it to an instance of the specified class using Sinobu's object mapping capabilities.
Automatic Decompression:
Sinobu automatically inspects the Content-Encoding
response header. If the content is
compressed using gzip
or deflate
, it will be decompressed transparently before
being passed to the type converter or returned as an InputStream
.
WebSocket Support
Sinobu provides a simple way to establish WebSocket connections using
I#http(String, Consumer, HttpClient...)
.
Communication is handled reactively using Signal
for incoming messages and a
WebSocket
object for sending messages.
Disposable connection = I.http("wss://echo.websocket.org", ws -> {
// Connection opened callback - send a message
System.out.println("WebSocket Opened!");
ws.sendText("Hello WebSocket!", true);
// You can send more messages later using the 'ws' object
// ws.sendText("Another message", true);
// Request more messages from the server (default is 1)
// ws.request(5); // Request up to 5 more messages
}).to(message -> { // onNext - received message
System.out.println("Received: " + message);
// ws.sendText("Got it: " + message, true); // Example: Echo back
}, error -> { // onError - connection error
System.err.println("WebSocket Error: " + error);
}, () -> { // onComplete - connection closed
System.out.println("WebSocket Closed");
});
// To close the connection later:
// connection.dispose();
The Consumer<WebSocket> open
lambda is executed once the connection is successfully
established.
The WebSocket
instance provided allows you to send messages (sendText
,
sendBinary
, sendPing
, etc.)
and manage the connection state (request
, sendClose
).
Incoming messages are received through the Signal
returned by I.http
.
Automatic Decompression:
Similar to HTTP responses, Sinobu automatically handles WebSocket messages compressed
with the
standard permessage-deflate
extension (commonly used for gzip/deflate over WebSockets),
ensuring you receive decompressed text messages in the Signal
.
Custom HttpClient
While I#http
methods use a default, shared HttpClient
instance
internally,
you can provide your own configured HttpClient
instance(s) as optional trailing
arguments
to any of the I.http
methods. This allows customization of timeouts, proxies, SSL
contexts,
authenticators, cookie handlers, etc., using the standard Java HttpClient.Builder
API.
HttpClient customClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.followRedirects(HttpClient.Redirect.NORMAL)
// .proxy(...)
// .sslContext(...)
// .authenticator(...)
// .cookieHandler(...)
.build();
// Use the custom client for the request
I.http("https://example.com", String.class, customClient).to(response -> { ... });
// Use it for WebSocket too
I.http("wss://example.com/ws", ws -> { ... }, customClient).to(message -> { ... });
If multiple clients are passed, the first non-null one is used. If none are provided or
all are null,
the default client (I.client
) is used.