Calco

Java

The Java connector uses java.net.http.HttpClient with no external dependencies. It needs Java 17+ to compile. Render methods return byte[].

Add the connector

There's no Maven/Gradle artifact to depend on (yet) — the client is a single, dependency-free class. Copy CalcoClient.java into your source tree under com/calco/, keeping its package com.calco; declaration, then import it:

java
import com.calco.CalcoClient;

Quick start

java
import com.calco.CalcoClient;
import java.nio.file.Path;
import java.time.Duration;

// With API key and custom timeout
var client = new CalcoClient(
    "http://localhost:8080",
    "dc_live_...",
    Duration.ofMinutes(5));

The key is sent as Authorization: Bearer <key> on every request. Pass null for no key.

Converting a file

java
byte[] pdf = client.convert(
    Path.of("report.xlsx"),
    "pdf",
    "{\"company\": \"Acme\"}", // dataJson
    "Summary",                  // sheet
    "Q4 Report");               // title

java.nio.file.Files.write(Path.of("report.pdf"), pdf);

Extract the placeholder map with scaffold:

java
String scaffold = client.scaffold(Path.of("spreadsheet.xlsx"));

Managing templates

java
// Create
String template = client.createTemplate(
    Path.of("template.xlsx"), "Invoice", "finance", "billing,monthly");

// List
String templates = client.listTemplates();

// Update metadata (null = unchanged)
client.updateTemplate("42", "Invoice v2", "accounting", null);

// Add a new version
client.createTemplateVersion("42", Path.of("template_v2.xlsx"));

// Delete
client.deleteTemplate("42");

Rendering a stored template

java
byte[] html = client.renderTemplateVersion(
    "42",                       // id
    "2",                        // version
    "html",                     // format
    "{\"customer\": \"Jane\"}", // dataJson
    null,                       // sheet
    "Invoice #1001");           // title

java.nio.file.Files.write(Path.of("invoice.html"), html);

Batch rendering

Pass a JSON array of records and receive a ZIP archive:

java
String records = "[{\"name\":\"Alice\",\"amount\":100},{\"name\":\"Bob\",\"amount\":200}]";

byte[] zip = client.batchRender(
    records,
    "42",               // templateId
    "1",                // version
    "pdf",              // format
    "invoice_{{name}}", // titleTemplate
    "Sheet1");          // sheet

java.nio.file.Files.write(Path.of("invoices.zip"), zip);

By-hash workflow

Every stored version exposes a content hash (sha256 of the file). Address a version directly by hash:

java
String meta = client.getTemplateByHash("3c9f...d1ab");
byte[] pdf  = client.renderByHash("3c9f...d1ab", "pdf", "{\"customer\":\"Jane\"}", null, null);
byte[] xlsx = client.downloadByHash("3c9f...d1ab", "xlsx", null, null, null);

Error handling

API errors throw CalcoClient.CalcoException, which carries the HTTP status code:

java
try {
    client.convert(Path.of("missing.xlsx"), "pdf", null, null, null);
} catch (CalcoClient.CalcoException e) {
    System.out.println("Status: " + e.getStatusCode());
    System.out.println("Message: " + e.getMessage());
}

Spring Boot integration

Bean configuration

java
import com.calco.CalcoClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;

@Configuration
public class CalcoConfig {
    @Bean
    public CalcoClient calcoClient(
            @Value("${calco.url}") String url,
            @Value("${calco.api-key:}") String apiKey) {
        return new CalcoClient(url, apiKey.isEmpty() ? null : apiKey, Duration.ofSeconds(120));
    }
}

Service and controller

java
@Service
public class ReportService {
    private final CalcoClient dc;

    public ReportService(CalcoClient dc) {
        this.dc = dc;
    }

    public byte[] convertToPdf(MultipartFile upload) throws IOException, InterruptedException {
        Path temp = Files.createTempFile("upload-", ".xlsx");
        try {
            upload.transferTo(temp);
            return dc.convert(temp, "pdf", null, null, null);
        } finally {
            Files.deleteIfExists(temp);
        }
    }
}

@RestController
@RequestMapping("/api/reports")
public class ReportController {
    private final ReportService reportService;

    public ReportController(ReportService reportService) {
        this.reportService = reportService;
    }

    @PostMapping("/convert")
    public ResponseEntity<byte[]> convert(@RequestParam("file") MultipartFile file) throws Exception {
        byte[] pdf = reportService.convertToPdf(file);
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=report.pdf")
                .contentType(MediaType.APPLICATION_PDF)
                .body(pdf);
    }
}

Configuration options

ParameterDefaultDescription
baseUrl—Root URL of the service (required)
apiKeynullBearer token for authentication
timeout120 secondsHTTP connect/request timeout