Kodall
Client SDKs

Java SDK (Java 21+)

Get started with the zero-dependency Java 21 client library for the Kodall platform.

The Kodall Java SDK (kodall-client-java) is a lightweight, high-performance REST client designed specifically for Java 21+. It features zero third-party runtime dependencies, relying entirely on standard JDK 21 libraries (java.net.http.HttpClient, Java Records, and Pattern Matching).


Requirements

  • JDK 21 or higher (Java 21 LTS, Java 23+)
  • Zero third-party runtime dependencies required.

Installation

Add the client dependency to your build tool configuration:

Add to your pom.xml:

XML
<dependency>
    <groupId>kodall</groupId>
    <artifactId>kodall-client-java</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

Quickstart

Initialize the client with your backend server URL and API key:

JAVA
import kodall.client.KodallClient;
import kodall.client.KodallClientConfig;
import kodall.client.exception.KodallApiException;
import java.util.List;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        // Configure client
        KodallClientConfig config = KodallClientConfig.newBuilder()
                .baseUrl("https://docs-demo.kodall.io")
                .apiKey("e3097afe-1528-4fdb-a816-0d3724a8f318")
                .build();

        KodallClient client = new KodallClient(config);

        // Execute a fetch query
        try {
            String query = """
                FETCH todo (key, title, is_completed)
                ORDER BY key DESC
                LIMIT 5
                """;

            List<Map<String, Object>> todos = client.fetch(query);
            for (Map<String, Object> todo : todos) {
                System.out.println("Todo #" + todo.get("key") + ": " + todo.get("title"));
            }
        } catch (KodallApiException e) {
            System.err.println("API Error (" + e.getStatusCode() + "): " + e.getMessage());
        }
    }
}

Client Configuration

The client is configured using the immutable KodallClientConfig builder:

JAVA
import kodall.client.KodallClient;
import kodall.client.KodallClientConfig;
import java.time.Duration;

// Stateless API Key mode (Microservices, background tasks)
KodallClientConfig apiKeyConfig = KodallClientConfig.newBuilder()
        .baseUrl("https://docs-demo.kodall.io")
        .apiKey("e3097afe-1528-4fdb-a816-0d3724a8f318")
        .connectTimeout(Duration.ofSeconds(10))
        .requestTimeout(Duration.ofSeconds(30))
        .build();

KodallClient client = new KodallClient(apiKeyConfig);

// Stateful Session Cookie mode (Desktop client, interactive CLI)
KodallClientConfig sessionConfig = KodallClientConfig.newBuilder()
        .baseUrl("https://docs-demo.kodall.io")
        .build();

KodallClient sessionClient = new KodallClient(sessionConfig);
Config OptionTypeDescription
baseUrl(String)StringBase endpoint URL (e.g. https://docs-demo.kodall.io).
apiKey(String)StringSecret API key used for stateless X-API-Key authentication.
connectTimeout(Duration)DurationHTTP connection establishment timeout (default: 10s).
requestTimeout(Duration)DurationIndividual HTTP request execution timeout (default: 30s).

Authentication

Basic Authentication (Username & Password)

JAVA
import kodall.client.KodallClient;
import kodall.client.KodallClientConfig;
import kodall.client.model.UserPassword;
import kodall.client.model.Session;
import kodall.client.exception.KodallApiException;

KodallClientConfig config = KodallClientConfig.newBuilder()
        .baseUrl("https://docs-demo.kodall.io")
        .build();
KodallClient client = new KodallClient(config);

try {
    UserPassword credentials = new UserPassword("root", "password123");
    Session session = client.auth(credentials);
    System.out.println("Authenticated as: " + session.userName());
} catch (KodallApiException e) {
    System.err.println("Authentication failed: " + e.getMessage());
}

OpenID Connect (OIDC / OAuth2)

JAVA
import kodall.client.model.OidcTokens;

Session session = client.auth(new OidcTokens("eyJhbGciOi...", "optionalRefreshToken"));

Session Lifecycle & Profile Switching

JAVA
import kodall.client.model.AuthOptions;
import kodall.client.model.UserProfile;
import java.util.List;

// Fetch current session with roles and available user profiles
Session session = client.session(new AuthOptions(true, true));
System.out.println("User roles: " + session.roles());

// Switch active user profile
client.changeUserProfile("sales_admin");

// Refresh active session cookie token
boolean refreshed = client.refreshSession();

// Logout
client.logout();

For more authentication details, visit the Auth API Reference.


Entity CRUD Operations

The Java SDK uses strongly typed immutable Java records (Entity, ChildEntity, Operation):

JAVA
import kodall.client.model.Entity;
import kodall.client.model.ChildEntity;
import kodall.client.model.Operation;
import kodall.client.exception.KodallValidationException;
import kodall.client.exception.KodallApiException;
import java.util.Map;
import java.util.List;

try {
    // 1. Create Entity with nested children
    Entity newTodo = new Entity("todo",
        Map.of("title", "Review Java 21 SDK", "is_completed", 0),
        Map.of("todo_todo_item", List.of(
            new ChildEntity("todo_item", Map.of("description", "Write documentation", "is_completed", 1))
        ))
    );

    Operation created = client.create(newTodo);
    long key = created.key();
    System.out.println("Created Entity Key: " + key);

    // 2. Retrieve Entity by Key
    Entity fetched = client.get("todo", key);
    System.out.println("Fetched properties: " + fetched.properties());

    // 3. Update Entity
    Entity updated = new Entity("todo", Map.of(
        "key", key,
        "title", "Review Java 21 SDK (Completed)",
        "is_completed", 1
    ));
    client.update(updated);

    // 4. Delete Entity
    client.delete("todo", key);

} catch (KodallValidationException e) {
    // HTTP 424: Business rule validation constraint violated
    System.err.println("Validation Error: " + e.getValidation().detail());
} catch (KodallApiException e) {
    System.err.println("API Error (" + e.getStatusCode() + "): " + e.getMessage());
}

For more entity operations and response structures, visit the Entities API Reference.


Fetch Query Engine

Query records flexibly as dynamic Map<String, Object> or bind directly to your own Java Records:

Dynamic Map Mapping

JAVA
String query = """
    FETCH todo (key, title, is_completed) {
      todo_item TO id_todo (key AS item_key, description, is_completed AS item_completed)
    }
    FILTER AND (is_completed == 0)
    """;

List<Map<String, Object>> rows = client.fetch(query);

Strongly Typed Java Record Mapping

Define a record matching your query projections:

JAVA
public record TodoSummary(long key, String title, int isCompleted) {}

// Directly map query results to your Java 21 record
List<TodoSummary> todos = client.fetch(
    "FETCH todo (key, title, is_completed AS isCompleted)",
    TodoSummary.class
);

for (TodoSummary todo : todos) {
    System.out.println(todo.title() + " (Key: " + todo.key() + ")");
}

AST Parsing & Metadata Inspection

JAVA
// Parse AST
Map<String, Object> ast = client.parseQuery("FETCH todo (key, title)");

// Inspect query columns metadata
Map<String, Object> metadata = client.fetchMetadata("FETCH todo (key, title)");

For more query syntax options, visit the Fetch API Reference.


Custom Workflows

Invoke server-side workflows by name and deserialize responses to custom types:

JAVA
public record WorkflowResponse(String message, String status) {}

Map<String, Object> payload = Map.of("name", "Java Developer", "type", "default");

WorkflowResponse response = client.workflow(
    "DemoWf",
    "hello",
    payload,
    WorkflowResponse.class
);

System.out.println("Workflow response: " + response.message());

For more workflow examples, visit the Workflow API Reference.


File Storage & Versioning

Upload, download, and version files with zero external HTTP form dependencies:

JAVA
import kodall.client.model.StorageItemResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

// 1. Upload a file
byte[] fileBytes = Files.readAllBytes(Path.of("report.pdf"));
List<StorageItemResponse> items = client.uploadFile(fileBytes, "report.pdf", null);
long fileId = items.get(0).id();

// 2. Upload a new version of the file
byte[] updatedBytes = Files.readAllBytes(Path.of("report_v2.pdf"));
client.uploadFileVersion(updatedBytes, "report.pdf", fileId);

// 3. Download file bytes
byte[] downloaded = client.getFile(fileId, null, "download");
Files.write(Path.of("downloaded_report.pdf"), downloaded);

For more storage operations, visit the Storage API Reference.


Error Handling

The Java SDK throws structured typed exceptions for precise error interception:

JAVA
import kodall.client.exception.KodallValidationException;
import kodall.client.exception.KodallApiException;

try {
    client.create(myEntity);
} catch (KodallValidationException e) {
    // HTTP 424: Business rule validation failure
    System.err.println("Event: " + e.getValidation().eventName());
    System.err.println("Entity: " + e.getValidation().entityName());
    System.err.println("Property: " + e.getValidation().propertyName());
    System.err.println("Constraint violation: " + e.getValidation().detail());
} catch (KodallApiException e) {
    // HTTP 400, 401, 403, 404, 500
    System.err.println("HTTP Status Code: " + e.getStatusCode());
    System.err.println("Error Detail: " + e.getMessage());
    if (e.getProblem() != null) {
        System.err.println("Problem Type: " + e.getProblem().type());
    }
}

Next Steps