Skip to main content

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 KoniferClient in Kotlin code that can call suspending functions.
  • Use KoniferBlockingClient in 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.

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()
}
}

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:

FailureMeaningAvailable details
Failure.HttpThe server returned a non-success HTTP status.statusCode and an optional message
Failure.TransportA network or response-body I/O operation failed.The underlying cause
Failure.InvalidResponseThe 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:

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)
}

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: