Releases: zigzap/zap
Release v0.11.0
ZAP Release v0.11.0
Updates
Update to Zig 0.15.1
This release introduces breaking changes that basically come from
"unmanaged" containers being the default in Zig's std library now. The
rest of Zap hasn't really changed much.
All examples and tests have been updated.
Also, the following contributions made it into the release:
- 3c22e9d - chore: update to latest zig version
- 512c630 - feat: tweak support for additional cookie fields
- 6174c3e - feat: add parition support for cookies in facil.io
Thanks Tesseract22 who kicked off the 0.15 work and Michael!
Using it
In your zig project folder (where build.zig is located), run:
zig fetch --save "git+https://github.com/zigzap/zap#v0.11.0"
Then, in your build.zig's build function, add the following before
b.installArtifact(exe):
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.root_module.addImport("zap", zap.module("zap"));Release v0.10.6
ZAP Release v0.10.6
Updates
Bugfix release:
The latest changes to parsing the mimetype of uploaded files required a
type check, as, apparently, they can also be arrays instead of
strings.
Using it
In your zig project folder (where build.zig is located), run:
zig fetch --save "git+https://github.com/zigzap/zap#v0.10.6"
Then, in your build.zig's build function, add the following before
b.installArtifact(exe):
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.root_module.addImport("zap", zap.module("zap"));Release v0.10.5
ZAP Release v0.10.5
Updates
A quick one. I was so fascinated by @TesseractCat's PR that I implemented
the same logic for all other forms of endpoints: regular endpoints,
authenticating endpoints, and middleware endpoints.
- see #171 from Tesseract22 : provide defaults to unprovided method
handlers in zap.App - the default handlers now return 405 - method not allowed, and also log
a message
I also fixed port numbers in tests so they don't cross-talk to each
other when run in parallel by the zig test runner.
Using it
In your zig project folder (where build.zig is located), run:
zig fetch --save "git+https://github.com/zigzap/zap#v0.10.5"
Then, in your build.zig's build function, add the following before
b.installArtifact(exe):
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.root_module.addImport("zap", zap.module("zap"));Release v0.10.4
ZAP Release v0.10.4
Updates
For some reason, the zon version hadn't come through before creating the
tag.
This time it will work 😄
Using it
In your zig project folder (where build.zig is located), run:
zig fetch --save "git+https://github.com/zigzap/zap#v0.10.4"
Then, in your build.zig's build function, add the following before
b.installArtifact(exe):
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.root_module.addImport("zap", zap.module("zap"));Release v0.10.3
ZAP Release v0.10.3
Updates
Sorry I (again) forgot to bump the version in build.zig.zon
To avoid confusion, I created this release. It's identical to v0.10.2,
but with the zon version fixed, so it will show up with the correct
version in your zon files after a zig fetch.
Using it
In your zig project folder (where build.zig is located), run:
zig fetch --save "git+https://github.com/zigzap/zap#v0.10.3"
Then, in your build.zig's build function, add the following before
b.installArtifact(exe):
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.root_module.addImport("zap", zap.module("zap"));Release v0.10.2
ZAP Release v0.10.2
Updates
Hi, it's been a while, and I've almost had no time for zap. However, ...
..., eventually I got to merge the following amazing PRs:
-
#171 from Tesseract22 : provide defaults to unprovided method handlers in
zap.App -
the default handlers now return 405 - method not allowed, and also log a
message -
#167 from yanis-fourel : file-uploads with missing content-type will default
to application/octet-stream -
#164 fwfurtado : added handlers for HEAD requests in Endpoints
-
#161 from unorsk : fixed example in the README
-
support for unhandledError() in zap.App's Context
Using it
In your zig project folder (where build.zig is located), run:
zig fetch --save "git+https://github.com/zigzap/zap#v0.10.2"
Then, in your build.zig's build function, add the following before
b.installArtifact(exe):
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.root_module.addImport("zap", zap.module("zap"));Release v0.10.1
ZAP Release v0.10.1
Updates
Rebased Zap's logging on Zig's std.log
Zap's logging is now based on zig's std.log.
You can set a custom log level just for Zap in your Zig projects like
this:
pub const std_options: std.Options = .{
// general log level
.log_level = .info,
.log_scope_levels = &[_]std.log.ScopeLevel{
// log level specific to zap
.{ .scope = .zap, .level = .debug },
},
};Low-level access to facil.io's logging facilities is provided by
zap.Logging.
Using it
In your zig project folder (where build.zig is located), run:
zig fetch --save "git+https://github.com/zigzap/zap#v0.10.1"
Then, in your build.zig's build function, add the following before
b.installArtifact(exe):
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.root_module.addImport("zap", zap.module("zap"));Release v0.10.0
ZAP Release v0.10.0
Updates
What's new in ZAP?
- Upgraded to Zig 0.14!
- Breaking Changes for
zap.Endpoint - New
zap.App! - Updated README
- Contributions!
After a break, I'm about to work a lot more with Zap, and in preparation made a few improvements which might also work in favor of newcomers.
BTW newcomers: please, also check out these other, pure-zig (which Zap is not) HTTP server projects:
- http.zig : Pure Zig! Close to Zap's model. Performance = good!
- jetzig : Comfortably develop modern web applications quickly, using http.zig under the hood
- zzz : Super promising, super-fast, especially for IO-heavy tasks, io_uring support - need I say more?
I can't wait for the day that Zap becomes obsolete. It would be a very good sign for the Zig HTTP server space!
Breaking Changes for zap.Endpoint
These breaking changes are meant to be improvements.
- no
@fieldParentPtr: Endpoints now directly get their@This()pointer passed into their methods - request handlers are allowed to return errors!
- the
.error_strategydecides if errors are logged to console or reported as HTML to the client (for debugging in the browser) - no "Settings":
pathanderror_strategyare required for Endpoints- all http method handlers must be present, but of course may be empty
- all of the above are checked at comptime, with meaningful compile error messages
- you register your custom Endpoint instances directly with the
zap.Endpoint.Listener, no need to provide an.endpoint()method.
It's best illustrated by example of error.zig (of the updated endpoints example) which creates the ErrorEndpoint:
//!
//! An ErrorEndpoint
//!
const std = @import("std");
const zap = @import("zap");
/// A simple endpoint listening on the /error route that causes an error on GET
/// requests, which gets logged to the response (=browser) by default
pub const ErrorEndpoint = @This();
path: []const u8 = "/error",
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
pub fn get(_: *ErrorEndpoint, _: zap.Request) !void {
return error.@"Oh-no!";
}
// unused:
pub fn post(_: *ErrorEndpoint, _: zap.Request) !void {}
pub fn put(_: *ErrorEndpoint, _: zap.Request) !void {}
pub fn delete(_: *ErrorEndpoint, _: zap.Request) !void {}
pub fn patch(_: *ErrorEndpoint, _: zap.Request) !void {}
pub fn options(_: *ErrorEndpoint, _: zap.Request) !void {}All relevant examples have been updated accordingly.
The New zap.App
In a way, zap.App takes the zap.Endpoint concept one step further: instead of having only per-endpoint instance data (fields of your Endpoint struct), endpoints in a zap.App easily share a global 'App Context'.
In addition to the global App Context, all Endpoint request handlers also receive an arena allocator for easy, care-free allocations. There is one arena allocator per thread, and arenas are reset after each request.
Just like regular / legacy zap.Endpoints, returning errors from request handlers is OK. It's decided on a per-endpoint basis how errors are dealt with, via the ErrorStrategy enum field.
Here is a complete zap.App example:
//!
//! Part of the Zap examples.
//!
//! Build me with `zig build app_basic`.
//! Run me with `zig build run-app_basic`.
//!
const std = @import("std");
const Allocator = std.mem.Allocator;
const zap = @import("zap");
// The global Application Context
const MyContext = struct {
db_connection: []const u8,
pub fn init(connection: []const u8) MyContext {
return .{
.db_connection = connection,
};
}
};
// A very simple endpoint handling only GET requests
const SimpleEndpoint = struct {
// zap.App.Endpoint Interface part
path: []const u8,
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
// data specific for this endpoint
some_data: []const u8,
pub fn init(path: []const u8, data: []const u8) SimpleEndpoint {
return .{
.path = path,
.some_data = data,
};
}
// handle GET requests
pub fn get(e: *SimpleEndpoint, arena: Allocator, context: *MyContext, r: zap.Request) !void {
const thread_id = std.Thread.getCurrentId();
r.setStatus(.ok);
// look, we use the arena allocator here -> no need to free the response_text later!
// and we also just `try` it, not worrying about errors
const response_text = try std.fmt.allocPrint(
arena,
\\Hello!
\\context.db_connection: {s}
\\endpoint.data: {s}
\\arena: {}
\\thread_id: {}
\\
,
.{ context.db_connection, e.some_data, arena.ptr, thread_id },
);
try r.sendBody(response_text);
std.time.sleep(std.time.ns_per_ms * 300);
}
// empty stubs for all other request methods
pub fn post(_: *SimpleEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
pub fn put(_: *SimpleEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
pub fn delete(_: *SimpleEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
pub fn patch(_: *SimpleEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
pub fn options(_: *SimpleEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
};
const StopEndpoint = struct {
path: []const u8,
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
pub fn get(_: *StopEndpoint, _: Allocator, context: *MyContext, _: zap.Request) !void {
std.debug.print(
\\Before I stop, let me dump the app context:
\\db_connection='{s}'
\\
\\
, .{context.*.db_connection});
zap.stop();
}
pub fn post(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
pub fn put(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
pub fn delete(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
pub fn patch(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
pub fn options(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
};
pub fn main() !void {
// setup allocations
var gpa: std.heap.GeneralPurposeAllocator(.{
// just to be explicit
.thread_safe = true,
}) = .{};
defer std.debug.print("\n\nLeaks detected: {}\n\n", .{gpa.deinit() != .ok});
const allocator = gpa.allocator();
// create an app context
var my_context = MyContext.init("db connection established!");
// create an App instance
const App = zap.App.Create(MyContext);
var app = try App.init(allocator, &my_context, .{});
defer app.deinit();
// create the endpoints
var my_endpoint = SimpleEndpoint.init("/test", "some endpoint specific data");
var stop_endpoint: StopEndpoint = .{ .path = "/stop" };
//
// register the endpoints with the app
try app.register(&my_endpoint);
try app.register(&stop_endpoint);
// listen on the network
try app.listen(.{
.interface = "0.0.0.0",
.port = 3000,
});
std.debug.print("Listening on 0.0.0.0:3000\n", .{});
std.debug.print(
\\ Try me via:
\\ curl http://localhost:3000/test
\\ Stop me via:
\\ curl http://localhost:3000/stop
\\
, .{});
// start worker threads -- only 1 process!!!
zap.start(.{
.threads = 2,
.workers = 1,
});
}Updated README
- restructured the examples section a bit
- got rid of all the microbenchmark stuff
- shout-outs to great Zap alternatives (http.zig, Jetzig, zzz)
Contributions!
Special thanks to:
- Victor Moin (vctrmn): Fix deprecated warning in facil.io #154
- Joshua B. (OsakiTsukiko): updated .gitignore, Endpoint improvements
- Thom Dickson (cosmicboots): Add type checking to simple_router's handle_func #125
What's coming up...?
I am contemplating upgrading the underlying facil.io library to the new and improved version 0.8!
Thanks for reading and helping out 😊!
Using it
In your zig project folder (where build.zig is located), run:
zig fetch --save "git+https://github.com/zigzap/zap#v0.10.0"
Then, in your build.zig's build function, add the following before
b.installArtifact(exe):
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.root_module.addImport("zap", zap.module("zap"));Release v0.9.1
ZAP Release v0.9.1
Updates
Bugfix for Middleware.EnpointHandler checkPath logic
I introduced a bug by wrongly trying to de-morgan the logic.
Thx @andr3h3nriqu3s11 for submitting issue #136 #136
I reverted the commit.
Using it
In your zig project folder (where build.zig is located), run:
zig fetch --save "git+https://github.com/zigzap/zap#v0.9.1"
Then, in your build.zig's build function, add the following before
b.installArtifact(exe):
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.root_module.addImport("zap", zap.module("zap"));Release v0.9.0
ZAP Release v0.9.0
Updates
Small API Refactors
This is a small update from recent PRs with little breaking changes in
zap.Mustache and zap.Middleware.EndpointHandler. Thanks for the
great contributions! See the changelog below.
Also: we now use zig fetch!
This greatly simplifies the instructions in the README and release
notes.
Breaking Changes:
Mustache:
- renamed
zap.Mustache.MustacheLoadArgstozap.Mustache.LoadArgs zap.Mustache.BuildResultis a public type now
Middleware:
zap.Middleware.EndpointHandlernow takes more than one option:
/// Options used to change the behavior of an `EndpointHandler`
pub const EndpointHandlerOptions = struct {
/// If `true`, the handler will stop handing requests down the chain if the
/// endpoint processed the request.
breakOnFinish: bool = true,
/// If `true`, the handler will only execute against requests that match
/// the endpoint's `path` setting.
checkPath: bool = false,
};I updated the docs and zig-master branch, too.
Changelog:
Rene Schallner (5):
Merge pull request #117 from cosmicboots/mustache-build
doc: getHeader need lowercase keys
Merge pull request #120 from cosmicboots/endpoint-middleware
Merge pull request #127 from iacore/patch-1
docs, announceybot: switch to using zig fetch
Thom Dickson (4):
include BuildResult in public Mustache API
rename MustacheLoadArgs to LoadArgs
Create options for EndpointHandler
update docs and examples for endpoint middleware
iacore (1):
update docs for zap.start
Using it
In your zig project folder (where build.zig is located), run:
zig fetch --save "git+https://github.com/zigzap/zap#v0.9.0"
Then, in your build.zig's build function, add the following before
b.installArtifact(exe):
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
.openssl = false, // set to true to enable TLS support
});
exe.root_module.addImport("zap", zap.module("zap"));