CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-dev-langchain4j--langchain4j-http-client

HTTP client abstraction for LangChain4j with synchronous/asynchronous execution and Server-Sent Events (SSE) streaming support

Overview
Eval results
Files

form-data-uploads.mddocs/guides/

Form Data and File Upload Guide

This guide covers multipart form data and file uploads using the LangChain4j HTTP Client.

Note: Form data support is experimental and was introduced in version 1.10.0.

Simple Form Data

Basic Form Data Request

import dev.langchain4j.http.client.*;

HttpRequest request = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/form")
    .addFormDataField("username", "alice")
    .addFormDataField("password", "secret")
    .addFormDataField("remember", "true")
    .build();

SuccessfulHttpResponse response = client.execute(request);

Form Data from Map

import java.util.Map;

Map<String, String> formData = Map.of(
    "username", "alice",
    "email", "alice@example.com",
    "subscribe", "true"
);

HttpRequest request = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/register")
    .formDataFields(formData)
    .build();

File Uploads

Single File Upload

import java.nio.file.Files;
import java.nio.file.Path;

byte[] fileContent = Files.readAllBytes(Path.of("/path/to/image.png"));

HttpRequest request = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/upload")
    .addFormDataField("title", "My Image")
    .addFormDataField("description", "A sample image")
    .addFormDataFile("image", "image.png", "image/png", fileContent)
    .build();

Multiple File Uploads

import java.nio.file.Files;
import java.nio.file.Path;

byte[] image1 = Files.readAllBytes(Path.of("/path/to/image1.png"));
byte[] image2 = Files.readAllBytes(Path.of("/path/to/image2.jpg"));

HttpRequest request = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/upload-multiple")
    .addFormDataFile("file1", "image1.png", "image/png", image1)
    .addFormDataFile("file2", "image2.jpg", "image/jpeg", image2)
    .build();

Upload with Metadata

byte[] fileContent = Files.readAllBytes(Path.of("/path/to/document.pdf"));

HttpRequest request = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/documents")
    .addFormDataField("title", "Contract")
    .addFormDataField("category", "legal")
    .addFormDataField("confidential", "true")
    .addFormDataFile("document", "contract.pdf", "application/pdf", fileContent)
    .build();

FormDataFile API

Creating FormDataFile Objects

import dev.langchain4j.http.client.FormDataFile;

byte[] content = Files.readAllBytes(Path.of("/path/to/file.txt"));

FormDataFile file = new FormDataFile(
    "file.txt",           // fileName
    "text/plain",         // contentType
    content               // file content as bytes
);

// Access properties
String fileName = file.fileName();
String contentType = file.contentType();
byte[] fileContent = file.content();

Upload from FormDataFile Map

import java.util.Map;

Map<String, FormDataFile> files = Map.of(
    "avatar", new FormDataFile("avatar.jpg", "image/jpeg", avatarBytes),
    "resume", new FormDataFile("resume.pdf", "application/pdf", resumeBytes)
);

HttpRequest request = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/profile")
    .formDataFiles(files)
    .build();

Common MIME Types

// Images
"image/png"
"image/jpeg"
"image/gif"
"image/webp"
"image/svg+xml"

// Documents
"application/pdf"
"application/msword"
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"  // .docx
"text/plain"
"text/csv"

// Archives
"application/zip"
"application/x-tar"
"application/gzip"

// Media
"video/mp4"
"audio/mpeg"
"audio/wav"

// Data
"application/json"
"application/xml"
"text/html"

Reading Files

From File System

import java.nio.file.Files;
import java.nio.file.Path;

Path filePath = Path.of("/path/to/file.jpg");
byte[] fileContent = Files.readAllBytes(filePath);

String contentType = Files.probeContentType(filePath);  // Auto-detect MIME type
if (contentType == null) {
    contentType = "application/octet-stream";  // Default binary type
}

HttpRequest request = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/upload")
    .addFormDataFile("file", filePath.getFileName().toString(), contentType, fileContent)
    .build();

From InputStream

import java.io.InputStream;

try (InputStream inputStream = getClass().getResourceAsStream("/resource.dat")) {
    byte[] content = inputStream.readAllBytes();

    HttpRequest request = HttpRequest.builder()
        .method(HttpMethod.POST)
        .url("https://api.example.com/upload")
        .addFormDataFile("resource", "resource.dat", "application/octet-stream", content)
        .build();
}

From URL

import java.net.URL;
import java.io.InputStream;

URL url = new URL("https://example.com/image.jpg");
try (InputStream inputStream = url.openStream()) {
    byte[] content = inputStream.readAllBytes();

    HttpRequest request = HttpRequest.builder()
        .method(HttpMethod.POST)
        .url("https://api.example.com/upload")
        .addFormDataFile("image", "downloaded-image.jpg", "image/jpeg", content)
        .build();
}

Validation and Constraints

Body vs Form Data Mutual Exclusion

Important: You cannot use both body() and form data (formDataFields() or formDataFiles()) in the same request.

// ❌ INVALID - Will throw IllegalArgumentException
HttpRequest request = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/upload")
    .body("{\"key\":\"value\"}")                    // Setting body
    .addFormDataField("field", "value")              // AND form data - ERROR!
    .build();

// ✅ VALID - Use either body OR form data
HttpRequest request1 = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/api")
    .body("{\"key\":\"value\"}")
    .build();

HttpRequest request2 = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/upload")
    .addFormDataField("field", "value")
    .build();

Empty File Handling

Calling addFormDataFile() with an empty byte array (length 0) is silently ignored.

byte[] emptyFile = new byte[0];

HttpRequest request = HttpRequest.builder()
    .method(HttpMethod.POST)
    .url("https://api.example.com/upload")
    .addFormDataFile("file", "empty.txt", "text/plain", emptyFile)  // Ignored
    .build();

Common Patterns

File Upload Factory

public class FileUploadClient {
    private final HttpClient client;
    private final String uploadUrl;

    public FileUploadClient(HttpClient client, String uploadUrl) {
        this.client = client;
        this.uploadUrl = uploadUrl;
    }

    public SuccessfulHttpResponse uploadFile(Path filePath, String fieldName) throws IOException {
        byte[] content = Files.readAllBytes(filePath);
        String fileName = filePath.getFileName().toString();
        String contentType = Files.probeContentType(filePath);

        if (contentType == null) {
            contentType = "application/octet-stream";
        }

        HttpRequest request = HttpRequest.builder()
            .method(HttpMethod.POST)
            .url(uploadUrl)
            .addFormDataFile(fieldName, fileName, contentType, content)
            .build();

        return client.execute(request);
    }

    public SuccessfulHttpResponse uploadWithMetadata(
            Path filePath,
            String fieldName,
            Map<String, String> metadata) throws IOException {

        byte[] content = Files.readAllBytes(filePath);
        String fileName = filePath.getFileName().toString();
        String contentType = Files.probeContentType(filePath);

        if (contentType == null) {
            contentType = "application/octet-stream";
        }

        HttpRequest.Builder builder = HttpRequest.builder()
            .method(HttpMethod.POST)
            .url(uploadUrl)
            .addFormDataFile(fieldName, fileName, contentType, content);

        // Add metadata fields
        for (Map.Entry<String, String> entry : metadata.entrySet()) {
            builder.addFormDataField(entry.getKey(), entry.getValue());
        }

        return client.execute(builder.build());
    }
}

Progress Tracking (Custom Implementation)

public class ProgressTrackingUpload {
    public void uploadWithProgress(Path filePath, Consumer<Integer> progressCallback) throws IOException {
        byte[] content = Files.readAllBytes(filePath);

        // Simulate progress (actual progress tracking requires custom HTTP client implementation)
        progressCallback.accept(0);

        HttpRequest request = HttpRequest.builder()
            .method(HttpMethod.POST)
            .url("https://api.example.com/upload")
            .addFormDataFile("file", filePath.getFileName().toString(),
                           Files.probeContentType(filePath), content)
            .build();

        progressCallback.accept(50);  // Upload started

        SuccessfulHttpResponse response = client.execute(request);

        progressCallback.accept(100);  // Upload complete
    }
}

Batch File Upload

public SuccessfulHttpResponse uploadMultipleFiles(List<Path> filePaths) throws IOException {
    HttpRequest.Builder builder = HttpRequest.builder()
        .method(HttpMethod.POST)
        .url("https://api.example.com/batch-upload");

    int index = 0;
    for (Path filePath : filePaths) {
        byte[] content = Files.readAllBytes(filePath);
        String fileName = filePath.getFileName().toString();
        String contentType = Files.probeContentType(filePath);

        if (contentType == null) {
            contentType = "application/octet-stream";
        }

        builder.addFormDataFile("file" + index, fileName, contentType, content);
        index++;
    }

    return client.execute(builder.build());
}

Error Handling

import dev.langchain4j.exception.HttpException;

try {
    byte[] fileContent = Files.readAllBytes(Path.of("/path/to/file.jpg"));

    HttpRequest request = HttpRequest.builder()
        .method(HttpMethod.POST)
        .url("https://api.example.com/upload")
        .addFormDataFile("file", "file.jpg", "image/jpeg", fileContent)
        .build();

    SuccessfulHttpResponse response = client.execute(request);
    System.out.println("Upload successful: " + response.body());

} catch (IOException e) {
    System.err.println("Failed to read file: " + e.getMessage());
} catch (HttpException e) {
    System.err.println("Upload failed with HTTP error: " + e.getMessage());
} catch (RuntimeException e) {
    System.err.println("Upload failed: " + e.getMessage());
}

Related Documentation

  • API Reference: Request Building API
  • Request Building: Synchronous Requests Guide
  • Error Handling: Error Handling Guide

Install with Tessl CLI

npx tessl i tessl/maven-dev-langchain4j--langchain4j-http-client@1.11.0

docs

index.md

installation.md

quick-start.md

tile.json