Konifer Client
Use the Konifer client to store images, retrieve their content or delivery URLs, update metadata, and evaluate rules
from your application. Client version 0.1.0 supports JVM 17 or newer. Kotlin/Native and JavaScript
targets are not part of this release... yet :).
Install the client
Add Maven Central to your project's repositories and include the client dependency.
Gradle:
implementation("io.konifer:konifer-client:0.1.0")
For a Java project using Gradle, use io.konifer:konifer-client-jvm:0.1.0.
Maven:
<dependency>
<groupId>io.konifer</groupId>
<artifactId>konifer-client-jvm</artifactId>
<version>0.1.0</version>
</dependency>
Choose your client
- Use
KoniferClientin Kotlin code that can call suspending functions. - Use
KoniferBlockingClientin Java or other JVM code that needs blocking calls. Each request blocks the calling thread.
Both clients expose the same operations and return KoniferResult<T>.
Create a client with your server's base URL, without the /assets suffix. Reuse it across requests, then close it at
application shutdown. The examples below create and close a client for a single program. In a Kotlin application,
call the suspending operations from your existing coroutine context.
Store an image and get its URL
Start a server using the Quickstart, and keep it running at
http://localhost:8080. Run this example from the documentation repository to use static/img/konifer-small.png,
or replace that filename with your own PNG. Each run stores a new entry at documentation/examples/profile-picture.
- Kotlin (suspending)
- Java (blocking)
import io.konifer.client.KoniferClient
import io.konifer.common.image.ImageFormat
import java.nio.file.Files
import java.nio.file.Path
suspend fun main() {
val client = KoniferClient.build("http://localhost:8080")
try {
val assets = client.assets("user/123/profile-picture")
val image = Files.readAllBytes(Path.of("static/img/konifer-small.png"))
val asset = assets.newAsset()
.fromBytes(image, ImageFormat.PNG)
.withAlt("Konifer logo")
.store()
.valueOrThrow()
val link = assets.entry(asset.entryId)
.originalVariant()
.fetchLink()
.valueOrThrow()
println("Stored entry: ${asset.entryId}")
println(link.url)
} finally {
client.close()
}
}
Save this program as Example.java.
import io.konifer.client.KoniferBlockingClient;
import io.konifer.common.image.ImageFormat;
import java.nio.file.Files;
import java.nio.file.Path;
public class Example {
public static void main(String[] args) throws Exception {
try (var client = KoniferBlockingClient.build("http://localhost:8080")) {
var assets = client.assets("user/123/profile-picture");
var image = Files.readAllBytes(Path.of("static/img/konifer-small.png"));
var asset = assets.newAsset()
.fromBytes(image, ImageFormat.PNG)
.withAlt("Konifer logo")
.store()
.valueOrThrow();
var link = assets.entry(asset.getEntryId())
.originalVariant()
.fetchLink()
.valueOrThrow();
}
}
}
Open the printed URL to view the image. The server's delivery configuration determines whether this URL points to Konifer, your object store, or a CDN. These examples buffer a small image in memory; use a streaming upload source for larger files.
Build requests
Start an asset operation with client.assets(path). For operations that select one asset, you select the newest entry
by default. Use entry(entryId) to select a specific version, as in the example above.
Chain modifiers to describe the request. Methods such as withAlt() and matchingLabels() return new request or
selection objects; keep the returned value or continue the chain. You send the request when you call an operation
such as store(), fetchInfo(), fetchLink(), update(), or deleteFirst().
For rule evaluation, start with client.ruleEvaluation(), choose an image source and definitions, then call
evaluate(). See the Rule Evaluation API for examples.
Handle results
Request operations return either KoniferResult.Success<T> with the response value or a KoniferResult.Failure:
| Failure | Meaning | Available details |
|---|---|---|
Failure.Http | The server returned a non-success HTTP status. | statusCode and an optional message |
Failure.Transport | A network or response-body I/O operation failed. | The underlying cause |
Failure.InvalidResponse | The client could not decode the response into the expected type. | The underlying cause |
Call valueOrThrow() if a request failure should abort your operation. This SDK method returns the successful value or
throws KoniferRequestException, an unchecked exception with the original failure in its failure property. For
transport and decoding failures, you can inspect the underlying exception through its cause.
Inspect the result instead if you need to recover from a particular failure. For example, you might treat a missing profile picture as an expected case:
- Kotlin (suspending)
- Java (blocking)
import io.konifer.client.KoniferRequestException
import io.konifer.client.KoniferResult
// Inside a suspending function, using your existing client:
when (val result = client.assets("users/123/profile-picture").fetchInfo()) {
is KoniferResult.Success -> println(result.value.entryId)
is KoniferResult.Failure.Http -> {
if (result.statusCode == 404) {
println("No profile picture yet.")
} else {
throw KoniferRequestException(result)
}
}
is KoniferResult.Failure -> throw KoniferRequestException(result)
}
import io.konifer.client.KoniferResult;
// Inside a method, using your existing blocking client:
var result = client.assets("users/123/profile-picture").fetchInfo();
if (result instanceof KoniferResult.Failure.Http http && http.getStatusCode() == 404) {
System.out.println("No profile picture yet.");
} else {
var asset = result.valueOrThrow();
System.out.println(asset.getEntryId());
}
You can handle the failures relevant to your application without branching on each failure type. Coroutine cancellation
and unexpected programming errors propagate as exceptions rather than KoniferResult.Failure values.
Optional configuration
Pass hmacKey to build() if your server requires signed retrieval URLs. Use the same
secret and signing algorithm as your server, and keep the secret in your application's secret configuration.
Use KoniferHttpConfiguration to set request, connection, or socket timeouts when creating the client. With the default
configuration, the client keeps the HTTP engine's timeout defaults and has no overall request deadline.
Next steps
Use the API reference's Kotlin and Java tabs for endpoint examples: