Ark supports multipart/form-data file uploads with binary fidelity across all 5 transports.
client.post("/upload")
.body(MultipartBody.builder()
.file("avatar", Path.of("photo.png"), "image/png")
.field("name", "Juan")
.build())
.retrieve()
.body(UploadResponse.class);byte[] pdfContent = generatePdf();
client.post("/documents")
.body(MultipartBody.builder()
.file("doc", pdfContent, "report.pdf", "application/pdf")
.field("title", "Monthly Report")
.build())
.retrieve()
.body(Document.class);client.post("/gallery")
.body(MultipartBody.builder()
.file("photos", Path.of("img1.jpg"), "image/jpeg")
.file("photos", Path.of("img2.jpg"), "image/jpeg")
.field("album", "Vacation")
.build())
.retrieve()
.body(Gallery.class);Use @RequestPart on method parameters:
@RegisterArkClient(configKey = "file-api")
@HttpExchange("/api")
public interface FileApi {
@PostExchange("/upload")
UploadResponse upload(@RequestPart("file") Path file, @RequestPart("name") String name);
@PostExchange("/upload")
UploadResponse uploadBytes(@RequestPart("data") byte[] data, @RequestPart("description") String desc);
}@RegisterArkClient(configKey = "file-api")
@Path("/api")
public interface FileApi {
@POST
@Path("/upload")
UploadResponse upload(@RequestPart("file") Path file, @RequestPart("name") String name);
}| Parameter type | Part type | Content-Type |
|---|---|---|
Path |
File part (reads bytes from disk) | Detected by magic bytes + extension |
byte[] |
File part | Detected by magic bytes |
| Any other type | Text field (String.valueOf()) |
- |
File content types are detected automatically by ContentTypeDetector:
-
Magic bytes (priority) - inspects first 12 bytes of the file:
- JPEG, PNG, GIF, WEBP, PDF, ZIP, GZIP, XML, JSON
-
Extension (fallback) - 25+ extensions mapped via
MimeTypeenum -
Default -
application/octet-streamif unrecognized
You can also specify the content type explicitly:
MultipartBody.builder()
.file("data", bytes, "custom.bin", "application/x-custom")
.build()- Magic bytes detection - does not trust file extensions alone
- Header sanitization - filenames and part names are sanitized to prevent MIME header injection (
",\r,\nescaped)
All 5 transports support binary multipart natively via sendBinary:
| Transport | Implementation |
|---|---|
| JDK HttpClient | BodyPublishers.ofByteArray() |
| Reactor Netty | Unpooled.wrappedBuffer() |
| Vert.x Mutiny | Buffer.buffer(byte[]) |
| Vert.x Future | Buffer.buffer(byte[]) |
| Apache HttpClient 5 | ByteArrayEntity |