Go
The Go connector uses only the standard library (net/http). Render methods
return []byte so you can write the result straight to disk or an HTTP response.
Add the connector
There's no published module to go get (yet) — the client is a single,
dependency-free Go file. Copy client.go into a package in your module (for
example a calco/ directory) and import that package. The examples below alias
it as dc:
import dc "yourmodule/calco"Quick start
package main
import (
"log"
"os"
"time"
dc "yourmodule/calco"
)
func main() {
client := dc.NewClient("http://localhost:8080", &dc.Options{
APIKey: "dc_live_...",
Timeout: 5 * time.Minute,
})
pdf, err := client.Convert("report.xlsx", "pdf", nil)
if err != nil {
log.Fatal(err)
}
os.WriteFile("report.pdf", pdf, 0644)
}NewClient(baseURL, *Options) accepts nil for defaults. The APIKey is sent
as Authorization: Bearer <key> on every request.
Converting a file
pdf, err := client.Convert("report.xlsx", "pdf", &dc.ConvertOptions{
DataJSON: `{"company": "Acme"}`,
Sheet: "Summary",
Title: "Q4 Report",
})Extract the placeholder map with Scaffold:
scaffold, err := client.Scaffold("spreadsheet.xlsx")
fmt.Println(string(scaffold))Managing templates
// Create
result, err := client.CreateTemplate("template.xlsx", "Invoice", "finance", "billing,monthly")
// List
templates, err := client.ListTemplates()
// Update metadata (empty string = unchanged)
_, err = client.UpdateTemplate("42", "Invoice v2", "accounting", "")
// Add a new version
_, err = client.CreateTemplateVersion("42", "template_v2.xlsx")
// Delete
_, err = client.DeleteTemplate("42")Rendering a stored template
html, err := client.RenderTemplateVersion("42", "2", "html", &dc.RenderOptions{
DataJSON: `{"customer": "Jane"}`,
Title: "Invoice #1001",
})
os.WriteFile("invoice.html", html, 0644)Batch rendering
Pass a JSON array of records and receive a ZIP archive:
records := `[{"name":"Alice","amount":100},{"name":"Bob","amount":200}]`
zip, err := client.BatchRender(records, "42", "1", "pdf", &dc.BatchRenderOptions{
TitleTemplate: "invoice_{{name}}",
Sheet: "Sheet1",
})
os.WriteFile("invoices.zip", zip, 0644)By-hash workflow
Every stored version exposes a content hash (sha256 of the file). Address a
version directly by hash:
meta, _ := client.GetTemplateByHash("3c9f...d1ab")
pdf, _ := client.RenderByHash("3c9f...d1ab", "pdf", &dc.RenderOptions{
DataJSON: `{"customer": "Jane"}`,
})
xlsx, _ := client.DownloadByHash("3c9f...d1ab", "xlsx", nil)Error handling
API errors are returned as *calco.Error with the HTTP status code and body.
Use errors.As to distinguish them from transport errors:
result, err := client.Convert("missing.xlsx", "pdf", nil)
if err != nil {
var apiErr *dc.Error
if errors.As(err, &apiErr) {
fmt.Printf("Status: %d\nBody: %s\n", apiErr.StatusCode, apiErr.Body)
} else {
fmt.Printf("Transport error: %v\n", err)
}
}Framework integration
Gin
client := dc.NewClient("http://localhost:8080", nil)
r := gin.Default()
r.POST("/export", func(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "file required"})
return
}
tmp := "/tmp/upload-" + file.Filename
if err := c.SaveUploadedFile(file, tmp); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer os.Remove(tmp)
format := c.DefaultPostForm("format", "pdf")
result, err := client.Convert(tmp, format, nil)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
c.Data(http.StatusOK, "application/octet-stream", result)
})
r.Run(":8080")Echo
e.POST("/export", func(c echo.Context) error {
file, err := c.FormFile("file")
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "file required")
}
src, _ := file.Open()
defer src.Close()
tmp, _ := os.CreateTemp("", "upload-*.xlsx")
defer os.Remove(tmp.Name())
io.Copy(tmp, src)
tmp.Close()
result, err := client.Convert(tmp.Name(), "pdf", nil)
if err != nil {
return echo.NewHTTPError(http.StatusBadGateway, err.Error())
}
return c.Blob(http.StatusOK, "application/octet-stream", result)
})Fiber
app.Post("/export", func(c *fiber.Ctx) error {
file, err := c.FormFile("file")
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "file required"})
}
tmp := "/tmp/upload-" + file.Filename
if err := c.SaveFile(file, tmp); err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
defer os.Remove(tmp)
result, err := client.Convert(tmp, c.FormValue("format", "pdf"), nil)
if err != nil {
return c.Status(502).JSON(fiber.Map{"error": err.Error()})
}
c.Set("Content-Type", "application/octet-stream")
return c.Send(result)
})Configuration options
| Field | Default | Description |
|---|---|---|
APIKey | "" | Bearer token for authentication |
Timeout | 120s | HTTP client timeout |
HTTPClient | nil | Optional pre-configured *http.Client |