HTTP client¶
MagicUtils HTTP client wraps java.net.http.HttpClient with config defaults,
JSON mapping, retries, and a small multipart helper.
Dependency¶
Configuration¶
The module stores settings in http-client.{ext} (JSONC by default on Fabric).
Key sections:
timeouts: connect + request timeoutsretry: backoff settings and retry status codeslogging: request/response logging togglesdefaults: base URL, headers, HTTP version
Basic usage¶
Platform platform = new BukkitPlatformProvider(this);
ConfigManager configManager = new ConfigManager(platform);
MagicHttpClient client = MagicHttpClient.builder(platform, configManager)
.baseUrl("https://api.example.com/")
.header("Authorization", "Bearer token")
.build();
HttpResponse<String> response = client.get("status");
Runtime profiles¶
When you already have a MagicRuntime, you can declare named HTTP/WebSocket
profiles that rebuild automatically on config reload:
MagicHttpClientProfile<ApiConfig> monitoring = MagicHttpClientProfile
.builder(runtime, "http.monitoring", ApiConfig.class)
.sections("monitoring")
.baseUrl(config -> config.monitoring.baseUrl)
.bearerAuth(config -> config.monitoring.token)
.build();
MagicHttpClient client = monitoring.require();
MagicHttpClient sameClient = runtime.requireNamedComponent("http.monitoring", MagicHttpClient.class);
MagicWebSocketClientProfile<ApiConfig> gateway = MagicWebSocketClientProfile
.builder(runtime, "ws.gateway", ApiConfig.class)
.sections("gateway")
.baseUrl(config -> config.gateway.baseUrl)
.bearerAuth(config -> config.gateway.token)
.subprotocols(config -> config.gateway.subprotocols)
.build();
This removes the usual close old client -> build new client -> swap references
boilerplate from service reload paths.
Smart methods¶
Smart methods switch to async automatically on blocking-sensitive threads and
return a CompletableFuture:
JSON to POJO¶
public record StatusResponse(String status) {}
StatusResponse response = client.getJson("status", StatusResponse.class);
JSON POST¶
Multipart upload¶
MultipartBody body = MultipartBody.builder()
.text("title", "Hello")
.file("file", Path.of("logo.png"))
.build();
client.postMultipart("upload", body);
WebSocket client¶
MagicWebSocketClient wraps java.net.http.WebSocket with the same builder
pattern and config integration as the HTTP client.
Basic usage¶
MagicWebSocketClient wsClient = MagicWebSocketClient.builder(platform, configManager)
.baseUrl("wss://api.example.com/ws")
.header("Authorization", "Bearer token")
.subprotocols(List.of("v1"))
.build();
CompletableFuture<WebSocket> ws = wsClient.connectAsync("/events", myListener);
Builder options¶
The builder supports the same options as MagicHttpClient.Builder:
baseUrl(...)— base URL prepended to connect pathsheader(...)/headers(...)— default headersuserAgent(...)— User-Agent headerconnectTimeout(...)— connection timeoutfollowRedirects(...)— redirect policysubprotocols(...)— WebSocket subprotocol listlogger(...)— platform logger for connection diagnosticsconfig(...)/logging(...)— sharedHttpClientConfigsettingsmapper(...)— custom JacksonObjectMapper
Connect methods¶
| Method | Description |
|---|---|
connect(path, listener) |
Synchronous connect (blocks). |
connectAsync(path, listener) |
Returns CompletableFuture<WebSocket>. |
connectSmart(path, listener) |
Async on blocking-sensitive threads, sync otherwise. |
Runtime profiles¶
Use MagicWebSocketClientProfile for config-aware WebSocket clients that
rebuild on config reload:
MagicWebSocketClientProfile<ApiConfig> gateway = MagicWebSocketClientProfile
.builder(runtime, "ws.gateway", ApiConfig.class)
.sections("gateway")
.baseUrl(config -> config.gateway.wsUrl)
.bearerAuth(config -> config.gateway.token)
.subprotocols(config -> config.gateway.subprotocols)
.build();
MagicWebSocketClient client = gateway.require();
Cleanup¶
Call wsClient.close() to release resources. When using runtime profiles, the
profile handles cleanup automatically on config reload and runtime shutdown.
Async method variants¶
Every convenience method on MagicHttpClient has three variants:
| Suffix | Behaviour |
|---|---|
| (none) | Synchronous. Throws on blocking-sensitive threads. |
...Async(...) |
Returns CompletableFuture. Always non-blocking. |
...Smart(...) |
Sync when safe, async when on a blocking-sensitive thread. |
Available methods: get, getJson, post, postJson, postMultipart,
send.
Notes¶
- Retries apply to the convenience methods (
get,post,postJson, etc.). - For raw
send(...), retries are not automatic. - JSON mapping uses Jackson; invalid JSON throws
IllegalStateException. - Synchronous methods throw
IllegalStateExceptionon blocking-sensitive threads. Use...Async()or...Smart()in handlers.