Releases: zigzap/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_strategy
decides if errors are logged to console or reported as HTML to the client (for debugging in the browser) - no "Settings":
path
anderror_strategy
are 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.MustacheLoadArgs
tozap.Mustache.LoadArgs
zap.Mustache.BuildResult
is a public type now
Middleware:
zap.Middleware.EndpointHandler
now 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"));
Release v0.8.0
ZAP Release v0.8.0
Updates
Update to Zig 0.13
With the help of our awesome contributers, we have a new release:
- Zap is now officially based on Zig 0.13.0!
- Thx to Lois Pearson, we now have
mimetypeRegister
andmimetypeClear
- Thx to geemili, we don't need to link facil.io in our build.zigs anymore
- Thx to Sören Michaels,
methodAsEnum
supports theHEAD
method. - ... and more, see the changelog below
Note: there now is a zig-master
branch that gets updated with breaking changes of Zig master on a somewhat regular basis. Please feel free to send PRs.
Many thanks again to everyone who helped out:
Giuseppe Cesarano (1):
fix: _debug typo in startWithLogging
Joe Koop (1):
update http.zig to rfc9110 using MDN as a reference
Lord Asdi (1):
fix: use std.process.getEnvVarOwned instead of std.posix.getenv
Louis Pearson (8):
fix: last_modifed -> last_modified
fix: docserver: server wasm with correct mimetype
feat: Wrap mimetypeRegister and mimetypeClear
fix: move getHeaderCommon to zap.zig
feat: add parseAccept
feat: make example for parseAccept
fix: simplify accept header api somewhat
feat: pre-allocate enough space for accept items
Michael Wendt (1):
feat: remove deprecated path
Rene Schallner (18):
Update hello_json.zig
fix docserver invocation from build.zig
proposed change to parseAccept API
make zap master build with zig master
update zig version
updated zig-master check in CI
update badge in README
corrected release templates
Sören Michaels (1):
feat: add HEAD Method to methodAsEnum
geemili (1):
feat: streamline depending on zap by linking facil.io to module
Using it
To use in your own projects, put this dependency into your build.zig.zon
:
// zap v0.8.0
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.8.0.tar.gz",
.hash = "12209936c3333b53b53edcf453b1670babb9ae8c2197b1ca627c01e72670e20c1a21",
}
Here is a complete build.zig.zon
example:
.{
.name = "My example project",
.version = "0.0.1",
.dependencies = .{
// zap v0.8.0
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.8.0.tar.gz",
.hash = "12209936c3333b53b53edcf453b1670babb9ae8c2197b1ca627c01e72670e20c1a21",
},
},
.paths = .{
"",
},
}
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.7.0
ZAP Release v0.7.0
Updates
Update to Zig 0.12
With the help of our awesome contributers, we have a new release:
- zap is now officially based on Zig 0.12.0!
- tests have been updated to use the latest
std.http
client - @desttinghim added
getHeaderCommon
tozap.Request
- @leroycep improved error return traces in
zap.Request.sendError()
- @dasimmet and @dweiller fixed the use of @fieldParentPtr to the new style
- @xflow-systems improved the write function of websockets
Users of sendError()
: the API has changed! The doc comment has been updated. The new way of using it is:
r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505);
The new version outputs much nicer error traces.
Note: there will likely be a zig-master
branch in the future that gets updated with breaking changes of Zig master. For sanity reasons, it will not be called zig-0.13.0
but zig-master
. I'll update the README accordingly then.
Note 2: I merged PRs and fixed the tests while waiting for my plane to board, then finished on the plane. If I might have rushed it and oopsied something up, I'll apologize and follow up with a bugfix release.
One open issue is using openssl on macOS, especially with openssl in custom locations, like homebrew-installed versions. If anyone wants to look into that: PRs are welcome 😊!
Many thanks again to everyone who helped out!
Using it
To use in your own projects, put this dependency into your build.zig.zon
:
// zap v0.7.0
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.7.0.tar.gz",
.hash = "1220a1cb1822ea77083045d246db5d7a6f07a8ddafa69c98dee367560f9ce667fd8d",
}
Here is a complete build.zig.zon
example:
.{
.name = "My example project",
.version = "0.0.1",
.dependencies = .{
// zap v0.7.0
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.7.0.tar.gz",
.hash = "1220a1cb1822ea77083045d246db5d7a6f07a8ddafa69c98dee367560f9ce667fd8d",
},
},
.paths = .{
"",
},
}
Then, in your build.zig
's build
function, add the following before exe.install()
:
const zap = b.dependency("zap", .{
.target = target,
.optimize = optimize,
});
exe.addModule("zap", zap.module("zap"));
exe.linkLibrary(zap.artifact("facil.io"));