Zig bindings for libcurl, a free and easy-to-use client-side URL transfer library.
This package supports the following Zig versions:
| Zig version | Branch |
|---|---|
0.17 | main |
0.16 | 0.16 |
0.15 | 0.15 |
The vendored libraries consist of:
| Library | Version |
|---|---|
| libcurl | 8.19.0 |
| zlib | 1.3.1 |
| mbedtls | 3.6.0 |
zig-curl provides two client interfaces designed for different use cases:
Client is modeled after Rust’s reqwest. It features fluent request chaining, strongly-typed JSON deserialization, and native integration with std.Io’s concurrency model. It also manages connection reuse and DNS caching across requests.
const std = @import("std");
const curl = @import("curl");
pub fn main(init: std.process.Init) !void {
var gpa: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{});
defer if (gpa.deinit() != 0) @panic("memory leak detected");
const allocator = gpa.allocator();
// 1. Initialize client (automatically loads system CA bundle & shares DNS/SSL cache)
var client = try curl.Client.init(allocator, init.io, .{});
defer client.deinit();
// 2. Fluent GET request
var res = try client.get("https://edgebin.liujiacai.net/ip")
.headers(&.{.{ .name = "Accept", .value = "application/json" }})
.timeout(10000)
.send(init.io);
defer res.deinit();
std.debug.print("Status: {d}\n", .{res.status_code});
// 3. Strongly-typed JSON deserialization directly from response
const IpGeo = struct { origin: []const u8, country: []const u8 };
const parsed = try res.json(IpGeo, .{ .ignore_unknown_fields = true });
defer parsed.deinit();
std.debug.print("IP: {s}, Country: {s}\n", .{ parsed.value.origin, parsed.value.country });
// 4. Asynchronous POST with body
var post_res = try client.post("https://edgebin.liujiacai.net/anything")
.headers(&.{.{ .name = "Content-Type", .value = "application/json" }})
.body("{\"message\": \"hello zig-curl\"}")
.send(init.io);
defer post_res.deinit();
}For concurrent batch requests using std.Io.Group, Bearer authentication, and worker pipeline patterns, see examples/client.zig.
Easy wraps libcurl’s curl_easy_* interface, providing direct control over transfers and streaming I/O.
const std = @import("std");
const curl = @import("curl");
const URL = "https://edgebin.liujiacai.net/anything";
pub fn main(init: std.process.Init) !void {
var gpa: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{});
defer if (gpa.deinit() != 0) @panic("memory leak detected");
const allocator = gpa.allocator();
var ca_bundle = try curl.allocCABundle(allocator, init.io);
defer ca_bundle.deinit(allocator);
var easy = try curl.Easy.init(.{
.ca_bundle = ca_bundle,
});
defer easy.deinit();
// 1. Simple GET without body
{
std.debug.print("GET without body\n", .{});
const response = try easy.fetch(URL, .{});
std.debug.print("Status code: {d}\n", .{response.status_code});
}
// 2. GET with streaming writer
{
std.debug.print("\nGET with fixed buffer as body\n", .{});
var buffer: [1024]u8 = undefined;
var writer = std.Io.Writer.fixed(&buffer);
const response = try easy.fetch(URL, .{ .writer = &writer });
std.debug.print("Status code: {d}\nBody: {s}\n", .{
response.status_code,
writer.buffered(),
});
}
}See examples/post.zig, examples/upload.zig, and examples/header.zig for more synchronous patterns.
When a curl operation fails, it returns a generic error.Curl. To get detailed libcurl error diagnostics, inspect the diagnostics field in Easy or Multi:
var easy = try curl.Easy.init(.{ ... });
defer easy.deinit();
easy.perform() catch |err| {
if (err == error.Curl) {
if (easy.diagnostics.getMessage()) |msg| {
std.log.err("curl failed: {s}", .{msg});
}
}
return err;
};# Latest version
zig fetch --save git+https://github.com/jiacai2050/zig-curl.git
# Tagged version
zig fetch --save git+https://github.com/jiacai2050/zig-curl.git#v0.5.0The latest tag can be found on release page.
After fetch, import curl like this in your build.zig:
const dep_curl = b.dependency("curl", .{});
exe.root_module.addImport("curl", dep_curl.module("curl"));
exe.root_module.link_libc = true;This library links to a vendored libcurl by default. To disable and link against system libcurl:
const dep_curl = b.dependency("curl", .{ .link_vendor = false });
exe.root_module.linkSystemLibrary("curl", .{});
exe.root_module.link_libc = true;