mirror of
https://github.com/zigzap/zap.git
synced 2026-01-29 09:06:58 +00:00
Adapt codebase to breaking API changes in Zig 0.16.0-dev: std.Io introduction: - std.io namespace renamed to std.Io (capitalization) - std.http.Client now requires io field - Create std.Io.Threaded at entry points, pass io to functions - Use std.Io.Writer.fixed() for fixed buffer writers - Use std.Io.Dir.cwd().access(io, ...) for file access checks Sleep API: - std.Thread.sleep / std.time.sleep removed - Use std.posix.nanosleep(seconds, nanoseconds) instead JSON API: - std.json.stringify() -> std.json.Stringify.value() Time API: - std.time.nanoTimestamp() removed - Use std.time.Instant.now() with .since() for durations File API: - readFileAlloc parameter order changed, uses std.Io.Limit Debug API: - std.debug.writeStackTrace signature changed (removed debugInfo) - Capture traces by pointer with |*trace| pattern Refactored Io pattern in tests/examples to create Threaded once at entry points and pass io: std.Io to helper functions, following Zig's new convention of treating Io like allocators. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
151 lines
4.9 KiB
Zig
151 lines
4.9 KiB
Zig
//!
|
|
//! Part of the Zap examples.
|
|
//!
|
|
//! Build me with `zig build http_params`.
|
|
//! Run me with `zig build run-http_params`.
|
|
//!
|
|
const std = @import("std");
|
|
const zap = @import("zap");
|
|
|
|
// set default log level to .info and ZAP log level to .debug
|
|
pub const std_options: std.Options = .{
|
|
.log_level = .info,
|
|
.log_scope_levels = &[_]std.log.ScopeLevel{
|
|
.{ .scope = .zap, .level = .debug },
|
|
},
|
|
};
|
|
|
|
// We send ourselves a request
|
|
fn makeRequest(a: std.mem.Allocator, io: std.Io, url: []const u8) !void {
|
|
var http_client: std.http.Client = .{ .allocator = a, .io = io };
|
|
defer http_client.deinit();
|
|
|
|
const response = try http_client.fetch(.{
|
|
.location = .{ .url = url },
|
|
.method = .GET,
|
|
.payload = null,
|
|
.keep_alive = false,
|
|
});
|
|
if (response.status.class() != .success) {
|
|
std.debug.print("HTTP Error: {?s}", .{response.status.phrase()});
|
|
}
|
|
}
|
|
|
|
fn makeRequestThread(a: std.mem.Allocator, io: std.Io, url: []const u8) !std.Thread {
|
|
return try std.Thread.spawn(.{}, makeRequest, .{ a, io, url });
|
|
}
|
|
|
|
// here we go
|
|
pub fn main() !void {
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
|
.thread_safe = true,
|
|
}){};
|
|
defer _ = gpa.detectLeaks();
|
|
|
|
const allocator = gpa.allocator();
|
|
|
|
const Handler = struct {
|
|
var alloc: std.mem.Allocator = undefined;
|
|
|
|
pub fn on_request(r: zap.Request) !void {
|
|
std.debug.print("\n=====================================================\n", .{});
|
|
defer std.debug.print("=====================================================\n\n", .{});
|
|
|
|
// check for FORM parameters
|
|
r.parseBody() catch |err| {
|
|
std.log.err("Parse Body error: {any}. Expected if body is empty", .{err});
|
|
};
|
|
|
|
// check for query parameters
|
|
r.parseQuery();
|
|
|
|
const param_count = r.getParamCount();
|
|
std.log.info("param_count: {}", .{param_count});
|
|
|
|
// ================================================================
|
|
// Access RAW params from querystring
|
|
// ================================================================
|
|
|
|
// let's get param "one" by name
|
|
std.debug.print("\n", .{});
|
|
if (r.getParamSlice("one")) |value| {
|
|
std.log.info("Param one = {s}", .{value});
|
|
} else {
|
|
std.log.info("Param one not found!", .{});
|
|
}
|
|
|
|
var arg_it = r.getParamSlices();
|
|
while (arg_it.next()) |param| {
|
|
std.log.info("ParamStr `{s}` is `{s}`", .{ param.name, param.value });
|
|
}
|
|
|
|
// ================================================================
|
|
// Access DECODED and typed params
|
|
// ================================================================
|
|
|
|
// iterate over all params as strings
|
|
var strparams = try r.parametersToOwnedStrList(alloc);
|
|
defer strparams.deinit();
|
|
std.debug.print("\n", .{});
|
|
for (strparams.items) |kv| {
|
|
std.log.info("ParamStr `{s}` is `{s}`", .{ kv.key, kv.value });
|
|
}
|
|
|
|
std.debug.print("\n", .{});
|
|
|
|
// iterate over all params
|
|
var params = try r.parametersToOwnedList(alloc);
|
|
defer params.deinit();
|
|
for (params.items) |kv| {
|
|
std.log.info("Param `{s}` is {any}", .{ kv.key, kv.value });
|
|
}
|
|
|
|
// let's get param "one" by name
|
|
std.debug.print("\n", .{});
|
|
if (r.getParamStr(alloc, "one")) |maybe_str| {
|
|
if (maybe_str) |s| {
|
|
defer alloc.free(s);
|
|
std.log.info("Param one = {s}", .{s});
|
|
} else {
|
|
std.log.info("Param one not found!", .{});
|
|
}
|
|
} else |err| {
|
|
std.log.err("cannot check for `one` param: {any}", .{err});
|
|
}
|
|
|
|
// check if we received a terminate=true parameter
|
|
if (r.getParamSlice("terminate")) |s| {
|
|
if (std.mem.eql(u8, s, "true")) {
|
|
zap.stop();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
Handler.alloc = allocator;
|
|
|
|
// setup listener
|
|
var listener = zap.HttpListener.init(
|
|
.{
|
|
.port = 3000,
|
|
.on_request = Handler.on_request,
|
|
.log = false,
|
|
.max_clients = 10,
|
|
.max_body_size = 1 * 1024,
|
|
},
|
|
);
|
|
|
|
try listener.listen();
|
|
std.log.info("\n\nTerminate with CTRL+C or by sending query param terminate=true", .{});
|
|
|
|
var threaded = std.Io.Threaded.init(allocator);
|
|
defer threaded.deinit();
|
|
const io = threaded.io();
|
|
|
|
const thread = try makeRequestThread(allocator, io, "http://127.0.0.1:3000/?one=1&two=2&string=hello+world&float=6.28&bool=true");
|
|
defer thread.join();
|
|
zap.start(.{
|
|
.threads = 1,
|
|
.workers = 1,
|
|
});
|
|
}
|