Skip to content

Instantly share code, notes, and snippets.

@Zorgatone
Last active November 13, 2025 03:06
Show Gist options
  • Select an option

  • Save Zorgatone/968ce86711aecea984a2c4a9771eed5f to your computer and use it in GitHub Desktop.

Select an option

Save Zorgatone/968ce86711aecea984a2c4a9771eed5f to your computer and use it in GitHub Desktop.
Zig 0.15.1 http-client GET example
const builtin = @import("builtin");
const std = @import("std");
// This version won't read/print headers, just the response
pub fn main() !void {
var writer_buffer: [8 * 1024]u8 = undefined;
var redirect_buffer: [8 * 1024]u8 = undefined;
var writer = std.fs.File.stdout().writer(&writer_buffer);
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
defer switch (builtin.mode) {
.Debug => std.debug.assert(debug_allocator.deinit() == .ok),
.ReleaseFast, .ReleaseSmall, .ReleaseSafe => {
// Nothing
},
};
const allocator = switch (builtin.mode) {
.Debug => debug_allocator.allocator(),
.ReleaseFast, .ReleaseSmall, .ReleaseSafe => std.heap.smp_allocator,
};
const uri = try std.Uri.parse("https://postman-echo.com/get");
var client: std.http.Client = .{ .allocator = allocator };
defer client.deinit();
const result = try client.fetch(.{
.location = .{ .uri = uri },
.method = .GET,
.redirect_buffer = &redirect_buffer,
.response_writer = &writer.interface,
});
if (builtin.mode == .Debug) {
std.debug.assert(result.status == .ok);
}
try writer.interface.flush();
}
const builtin = @import("builtin");
const std = @import("std");
// Manual http request printing also the response headers (won't work if chunked or compressed)
pub fn main() !void {
var writer_buffer: [8 * 1024]u8 = undefined;
var redirect_buffer: [8 * 1024]u8 = undefined;
var transfer_buffer: [8 * 1024]u8 = undefined;
var reader_buffer: [8 * 1024]u8 = undefined;
var writer = std.fs.File.stdout().writer(&writer_buffer);
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
defer switch (builtin.mode) {
.Debug => std.debug.assert(debug_allocator.deinit() == .ok),
.ReleaseFast, .ReleaseSmall, .ReleaseSafe => {
// Nothing
},
};
const allocator = switch (builtin.mode) {
.Debug => debug_allocator.allocator(),
.ReleaseFast, .ReleaseSmall, .ReleaseSafe => std.heap.smp_allocator,
};
const uri = try std.Uri.parse("https://postman-echo.com/get");
var client: std.http.Client = .{ .allocator = allocator };
defer client.deinit();
var request = try client.request(.GET, uri, .{});
defer request.deinit();
try request.sendBodiless();
const response = try request.receiveHead(&redirect_buffer);
_ = try writer.interface.write(response.head.bytes);
const content_length = response.head.content_length;
const reader = request.reader.bodyReader(&transfer_buffer, .none, content_length);
var done = false;
var bytes_read: usize = 0;
while (!done) {
const size = try reader.readSliceShort(&reader_buffer);
if (size > 0) {
bytes_read += size;
_ = try writer.interface.write(reader_buffer[0..size]);
}
if (content_length) |c_len| {
if (bytes_read >= c_len) {
done = true;
}
}
if (size < reader_buffer.len) {
done = true;
}
}
try writer.interface.flush();
}
@definitepotato
Copy link

@Zorgatone

Thanks for this. #1 makes sense. #2 your perspective is helping me understand zig better. Your explanation makes sense to me.

@bhagatverma
Copy link

I have written a working http request example for POST, PUT, GET, DELETE in ZIG 0.15.1/0.15.2
it also include headers, payload
https://github.com/bhagatverma/zig-http-request-example/blob/main/main.zig

@Zorgatone
Copy link
Author

@bhagatverma I checked your implementation:

    // Buffer for response body
    var response_body: std.ArrayList(u8) = .empty;
    defer response_body.deinit(allocator);

You're declaring an arrayList that is never used elsewhere, initialized and deinitialized only, and not actually needed

@Zorgatone
Copy link
Author

@bhagatverma also why declaring an identical enum?

pub const HttpMethod = enum {
    GET,
    POST,
    PUT,
    DELETE,
    PATCH,
    HEAD,
    OPTIONS,

    pub fn toStdMethod(self: HttpMethod) std.http.Method {
        return switch (self) {
            .GET => .GET,
            .POST => .POST,
            .PUT => .PUT,
            .DELETE => .DELETE,
            .PATCH => .PATCH,
            .HEAD => .HEAD,
            .OPTIONS => .OPTIONS,
        };
    }
};

instead of all that you could just use the standard std.http.Method yourself

@bhagatverma
Copy link

@bhagatverma I checked your implementation:

    // Buffer for response body
    var response_body: std.ArrayList(u8) = .empty;
    defer response_body.deinit(allocator);

You're declaring an arrayList that is never used elsewhere, initialized and deinitialized only, and not actually needed

Hi @Zorgatone , Thanks for pointing out, i missed to remove this unwanted code.

@bhagatverma
Copy link

@bhagatverma also why declaring an identical enum?

pub const HttpMethod = enum {
    GET,
    POST,
    PUT,
    DELETE,
    PATCH,
    HEAD,
    OPTIONS,

    pub fn toStdMethod(self: HttpMethod) std.http.Method {
        return switch (self) {
            .GET => .GET,
            .POST => .POST,
            .PUT => .PUT,
            .DELETE => .DELETE,
            .PATCH => .PATCH,
            .HEAD => .HEAD,
            .OPTIONS => .OPTIONS,
        };
    }
};

instead of all that you could just use the standard std.http.Method yourself

@Zorgatone you are absolutely right, i could have used std.http instead of enum. but its just another way of writing same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment