KissRequests AI Skill v0.1.0
This Markdown file is a versioned AI skill for using KissRequests in other Java projects. It is intentionally self-contained so an AI assistant can load this one document, add the Maven dependency, write consumer code, and avoid inventing APIs.
Use this skill for release 0.1.0. If the repository source is on a later -SNAPSHOT, consumer documentation should still use 0.1.0 unless the user explicitly asks for a snapshot build.
Library Summary
Tiny zero-dependency Java 17+ HTTP client facade over java.net.http.HttpClient with prepared calls, retries, file upload/download, streaming, multipart, and curl rendering.
Maven Dependency
<dependency>
<groupId>io.github.arthurhoch</groupId>
<artifactId>kiss-requests</artifactId>
<version>0.1.0</version>
</dependency>
AI Usage Rules
- Target Java 17 or newer.
- Prefer the public package rooted at
io.github.arthurhoch.kissrequests. - Do not invent convenience APIs. Use only the public members listed in this file or in generated Javadocs for the same release.
- Keep examples small and explicit, matching the KISS philosophy.
- Do not add extra frameworks unless the consuming project already uses them.
- Keep older skill files in place when a new release is documented.
Quick Example
Http http = Http.create();
HttpResult result = http.request(HttpMethod.GET, "https://example.com")
.execute();
System.out.println(result.statusCode());
System.out.println(result.body());
How To Use The Library
Http.create()creates a reusable client with default timeout, retry, concurrency, and executor settings.Http.builder()customizes shared client behavior. Build one instance and reuse it for a target integration.- Every request factory returns an immutable
HttpCall<T>. Nothing is sent untilexecute()is called. - Use
toCurl()ortoCurlBase64()for diagnostics before executing or when reporting an error. Treat curl output as sensitive when headers or bodies contain secrets. - Use string method constants from
HttpMethod; custom methods are still accepted as nonblank strings. - Do not import
io.github.arthurhoch.kissrequests.internal.*in consumer projects. Those classes are implementation details, even though some are public for package architecture.
Behavioral Contract For v0.1.0
HttpMethodis a constants class, not an enum. Constants areGET,POST,PUT,DELETE,PATCH,HEAD, andOPTIONS.RetryPolicy.defaults()performs one attempt.RetryPolicy.of(...)enables conservative retries for status codes 429, 500, 502, 503, and 504 on idempotent methods by default.HttpResultis used by text, upload, and multipart calls.HttpDownloadResultstores the target path and byte count.HttpStreamResultexposes anInputStream; the caller owns closing it.HttpExceptioncarries method, URL, curl command, attempts, total duration, response status, headers, truncated response body, and root cause. Usereport()for human diagnostics.uploadstreams one file as the request body.downloadwrites the response body to disk.multipartbuilds amultipart/form-datarequest from text fields and file fields.- Headers maps passed to the API may be
null; null headers are treated as empty. Method and URL must be non-null and nonblank.
Practical Examples
Reusable client with retries
Http http = Http.builder()
.connectTimeout(Duration.ofSeconds(5))
.requestTimeout(Duration.ofSeconds(20))
.retryPolicy(RetryPolicy.of(3, Duration.ofMillis(250)))
.maxConcurrentRequests(32)
.build();
File download
Path target = Path.of("response.bin");
HttpDownloadResult download = http
.download(HttpMethod.GET, "https://example.com/file", Map.of(), target)
.execute();
System.out.println(download.bytesWritten());
Public API Specification
The following index is generated from compiled public classes with javap -public. It includes public constructors, constants, enum methods, record accessors, inherited Object overrides when public, and public nested classes.
When an internal package appears here, treat it as implementation detail unless the project documentation explicitly says otherwise. Consumer code should prefer the public surface described above.
public final class io.github.arthurhoch.kissrequests.Http {
public static io.github.arthurhoch.kissrequests.Http create();
public static io.github.arthurhoch.kissrequests.Http$Builder builder();
public io.github.arthurhoch.kissrequests.HttpCall<io.github.arthurhoch.kissrequests.HttpResult> request(java.lang.String, java.lang.String);
public io.github.arthurhoch.kissrequests.HttpCall<io.github.arthurhoch.kissrequests.HttpResult> request(java.lang.String, java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
public io.github.arthurhoch.kissrequests.HttpCall<io.github.arthurhoch.kissrequests.HttpResult> request(java.lang.String, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.lang.String);
public io.github.arthurhoch.kissrequests.HttpCall<io.github.arthurhoch.kissrequests.HttpResult> upload(java.lang.String, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.nio.file.Path);
public io.github.arthurhoch.kissrequests.HttpCall<io.github.arthurhoch.kissrequests.HttpDownloadResult> download(java.lang.String, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.nio.file.Path);
public io.github.arthurhoch.kissrequests.HttpCall<io.github.arthurhoch.kissrequests.HttpStreamResult> stream(java.lang.String, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.lang.String);
public io.github.arthurhoch.kissrequests.HttpCall<io.github.arthurhoch.kissrequests.HttpResult> multipart(java.lang.String, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.util.Map<java.lang.String, java.lang.String>, java.util.Map<java.lang.String, java.nio.file.Path>);
}
public final class io.github.arthurhoch.kissrequests.Http$Builder {
public io.github.arthurhoch.kissrequests.Http$Builder();
public io.github.arthurhoch.kissrequests.Http$Builder connectTimeout(java.time.Duration);
public io.github.arthurhoch.kissrequests.Http$Builder requestTimeout(java.time.Duration);
public io.github.arthurhoch.kissrequests.Http$Builder retryPolicy(io.github.arthurhoch.kissrequests.RetryPolicy);
public io.github.arthurhoch.kissrequests.Http$Builder maxConcurrentRequests(int);
public io.github.arthurhoch.kissrequests.Http$Builder executor(java.util.concurrent.Executor);
public io.github.arthurhoch.kissrequests.Http build();
}
public final class io.github.arthurhoch.kissrequests.HttpAttempt extends java.lang.Record {
public io.github.arthurhoch.kissrequests.HttpAttempt(int, int, java.time.Duration, java.lang.String);
public final java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public int attemptNumber();
public int statusCode();
public java.time.Duration duration();
public java.lang.String failureMessage();
}
public final class io.github.arthurhoch.kissrequests.HttpCall<T> {
public T execute();
public java.lang.String toCurl();
public java.lang.String toCurlBase64();
public java.lang.String method();
public java.lang.String url();
public java.util.Map<java.lang.String, java.lang.String> headers();
public java.lang.String body();
public java.nio.file.Path file();
public java.nio.file.Path targetPath();
public java.util.Map<java.lang.String, java.lang.String> fields();
public java.util.Map<java.lang.String, java.nio.file.Path> fileFields();
public io.github.arthurhoch.kissrequests.internal.CallType callType();
}
public final class io.github.arthurhoch.kissrequests.HttpConfig extends java.lang.Record {
public io.github.arthurhoch.kissrequests.HttpConfig(java.time.Duration, java.time.Duration, io.github.arthurhoch.kissrequests.RetryPolicy, int, java.util.concurrent.Executor);
public static io.github.arthurhoch.kissrequests.HttpConfig defaults();
public final java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public java.time.Duration connectTimeout();
public java.time.Duration requestTimeout();
public io.github.arthurhoch.kissrequests.RetryPolicy retryPolicy();
public int maxConcurrentRequests();
public java.util.concurrent.Executor executor();
}
public final class io.github.arthurhoch.kissrequests.HttpDownloadResult extends java.lang.Record {
public io.github.arthurhoch.kissrequests.HttpDownloadResult(int, java.util.Map<java.lang.String, java.util.List<java.lang.String>>, java.nio.file.Path, long, java.time.Duration, java.util.List<io.github.arthurhoch.kissrequests.HttpAttempt>, java.lang.String, java.lang.String);
public final java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public int statusCode();
public java.util.Map<java.lang.String, java.util.List<java.lang.String>> headers();
public java.nio.file.Path file();
public long bytesWritten();
public java.time.Duration duration();
public java.util.List<io.github.arthurhoch.kissrequests.HttpAttempt> attempts();
public java.lang.String method();
public java.lang.String url();
}
public class io.github.arthurhoch.kissrequests.HttpException extends java.lang.RuntimeException {
public io.github.arthurhoch.kissrequests.HttpException(java.lang.String, java.lang.String, java.lang.String, java.util.List<io.github.arthurhoch.kissrequests.HttpAttempt>, java.time.Duration, int, java.util.Map<java.lang.String, java.util.List<java.lang.String>>, java.lang.String, java.lang.Throwable);
public java.lang.String method();
public java.lang.String url();
public java.lang.String curl();
public java.util.List<io.github.arthurhoch.kissrequests.HttpAttempt> attempts();
public java.time.Duration totalDuration();
public int statusCode();
public java.util.Map<java.lang.String, java.util.List<java.lang.String>> responseHeaders();
public java.lang.String responseBody();
public synchronized java.lang.Throwable getCause();
public java.lang.Throwable rootCause();
public java.lang.String report();
public static java.lang.String truncateBody(java.lang.String);
}
public final class io.github.arthurhoch.kissrequests.HttpMethod {
public static final java.lang.String GET;
public static final java.lang.String POST;
public static final java.lang.String PUT;
public static final java.lang.String DELETE;
public static final java.lang.String PATCH;
public static final java.lang.String HEAD;
public static final java.lang.String OPTIONS;
}
public final class io.github.arthurhoch.kissrequests.HttpResult extends java.lang.Record {
public io.github.arthurhoch.kissrequests.HttpResult(int, java.util.Map<java.lang.String, java.util.List<java.lang.String>>, java.lang.String, java.time.Duration, java.util.List<io.github.arthurhoch.kissrequests.HttpAttempt>, java.lang.String, java.lang.String);
public final java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public int statusCode();
public java.util.Map<java.lang.String, java.util.List<java.lang.String>> headers();
public java.lang.String body();
public java.time.Duration duration();
public java.util.List<io.github.arthurhoch.kissrequests.HttpAttempt> attempts();
public java.lang.String method();
public java.lang.String url();
}
public final class io.github.arthurhoch.kissrequests.HttpStreamResult extends java.lang.Record {
public io.github.arthurhoch.kissrequests.HttpStreamResult(int, java.util.Map<java.lang.String, java.util.List<java.lang.String>>, java.io.InputStream, java.time.Duration, java.util.List<io.github.arthurhoch.kissrequests.HttpAttempt>, java.lang.String, java.lang.String);
public final java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public int statusCode();
public java.util.Map<java.lang.String, java.util.List<java.lang.String>> headers();
public java.io.InputStream inputStream();
public java.time.Duration duration();
public java.util.List<io.github.arthurhoch.kissrequests.HttpAttempt> attempts();
public java.lang.String method();
public java.lang.String url();
}
public final class io.github.arthurhoch.kissrequests.RetryPolicy {
public static io.github.arthurhoch.kissrequests.RetryPolicy defaults();
public static io.github.arthurhoch.kissrequests.RetryPolicy of(int);
public static io.github.arthurhoch.kissrequests.RetryPolicy of(int, java.time.Duration);
public static io.github.arthurhoch.kissrequests.RetryPolicy of(int, java.time.Duration, java.util.Set<java.lang.Integer>, java.util.Set<java.lang.String>);
public int maxAttempts();
public java.time.Duration initialBackoff();
public java.util.Set<java.lang.Integer> retryOnStatusCodes();
public java.util.Set<java.lang.String> retryOnMethods();
public boolean shouldRetryOnStatus(int);
public boolean shouldRetryMethod(java.lang.String);
}
public final class io.github.arthurhoch.kissrequests.internal.CallType extends java.lang.Enum<io.github.arthurhoch.kissrequests.internal.CallType> {
public static final io.github.arthurhoch.kissrequests.internal.CallType TEXT;
public static final io.github.arthurhoch.kissrequests.internal.CallType UPLOAD;
public static final io.github.arthurhoch.kissrequests.internal.CallType DOWNLOAD;
public static final io.github.arthurhoch.kissrequests.internal.CallType STREAM;
public static final io.github.arthurhoch.kissrequests.internal.CallType MULTIPART;
public static io.github.arthurhoch.kissrequests.internal.CallType[] values();
public static io.github.arthurhoch.kissrequests.internal.CallType valueOf(java.lang.String);
}
public final class io.github.arthurhoch.kissrequests.internal.ConcurrencyLimiter {
public io.github.arthurhoch.kissrequests.internal.ConcurrencyLimiter(int);
public io.github.arthurhoch.kissrequests.internal.ConcurrencyLimiter$Token acquire() throws java.lang.InterruptedException;
}
public final class io.github.arthurhoch.kissrequests.internal.ConcurrencyLimiter$Token {
public void release();
}
public final class io.github.arthurhoch.kissrequests.internal.CurlRenderer {
public static java.lang.String render(io.github.arthurhoch.kissrequests.HttpCall<?>);
}
public final class io.github.arthurhoch.kissrequests.internal.HttpExecutionEngine {
public io.github.arthurhoch.kissrequests.internal.HttpExecutionEngine(java.net.http.HttpClient, io.github.arthurhoch.kissrequests.HttpConfig);
public java.lang.Object execute(io.github.arthurhoch.kissrequests.HttpCall<?>);
}
public final class io.github.arthurhoch.kissrequests.internal.MultipartBodyBuilder {
public static java.lang.String generateBoundary();
public static java.net.http.HttpRequest$BodyPublisher buildBody(java.util.Map<java.lang.String, java.lang.String>, java.util.Map<java.lang.String, java.nio.file.Path>, java.lang.String) throws java.io.IOException;
public static long computeContentLength(java.util.Map<java.lang.String, java.lang.String>, java.util.Map<java.lang.String, java.nio.file.Path>, java.lang.String);
}
Local Verification Commands
Run these commands in the KissRequests repository when changing examples, docs, or release skill files:
mvn -B clean verify
mvn -B javadoc:javadoc
Release Skill Maintenance
For a future release such as 0.2.0, create a new file at docs/skills/v0.2.0.md instead of editing or deleting this historical file. Update docs/skills/index.md with a view link and a raw download link for the new version.