HTTP client abstraction for LangChain4j with synchronous/asynchronous execution and Server-Sent Events (SSE) streaming support
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.
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);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();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();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();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();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();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();// 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"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();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();
}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();
}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();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();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());
}
}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
}
}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());
}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());
}Install with Tessl CLI
npx tessl i tessl/maven-dev-langchain4j--langchain4j-http-client@1.11.0