1
0
Fork 0
mirror of https://github.com/zigzap/zap.git synced 2025-10-20 15:14:08 +00:00

endpoints, auth endpoints, middleware endpoints: eliminate need for empty stubs

This commit is contained in:
renerocksai 2025-07-23 20:23:49 +02:00
parent baaa71d0e0
commit dabd0637f9
No known key found for this signature in database
9 changed files with 59 additions and 80 deletions

View file

@ -59,7 +59,7 @@ const SimpleEndpoint = struct {
try r.sendBody(response_text); try r.sendBody(response_text);
std.time.sleep(std.time.ns_per_ms * 300); std.time.sleep(std.time.ns_per_ms * 300);
} }
}; };
const StopEndpoint = struct { const StopEndpoint = struct {
path: []const u8, path: []const u8,

View file

@ -13,11 +13,3 @@ pub fn get(_: *ErrorEndpoint, _: zap.Request) !void {
// --> this error will be shown in the browser, with a nice error trace // --> this error will be shown in the browser, with a nice error trace
return error.@"Oh-no!"; 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 {}
pub fn head(_: *ErrorEndpoint, _: zap.Request) !void {}

View file

@ -17,10 +17,3 @@ pub fn init(path: []const u8) StopEndpoint {
pub fn get(_: *StopEndpoint, _: zap.Request) !void { pub fn get(_: *StopEndpoint, _: zap.Request) !void {
zap.stop(); zap.stop();
} }
pub fn post(_: *StopEndpoint, _: zap.Request) !void {}
pub fn put(_: *StopEndpoint, _: zap.Request) !void {}
pub fn delete(_: *StopEndpoint, _: zap.Request) !void {}
pub fn patch(_: *StopEndpoint, _: zap.Request) !void {}
pub fn options(_: *StopEndpoint, _: zap.Request) !void {}
pub fn head(_: *StopEndpoint, _: zap.Request) !void {}

View file

@ -43,7 +43,8 @@ fn userIdFromPath(self: *UserWeb, path: []const u8) ?usize {
return null; return null;
} }
pub fn put(_: *UserWeb, _: zap.Request) !void {} // not implemented
// pub fn put(_: *UserWeb, _: zap.Request) !void {}
pub fn get(self: *UserWeb, r: zap.Request) !void { pub fn get(self: *UserWeb, r: zap.Request) !void {
if (r.path) |path| { if (r.path) |path| {

View file

@ -31,14 +31,6 @@ const Endpoint = struct {
r.setStatus(.unauthorized); r.setStatus(.unauthorized);
r.sendBody("UNAUTHORIZED ACCESS") catch return; r.sendBody("UNAUTHORIZED ACCESS") catch return;
} }
// not implemented, don't care
pub fn post(_: *Endpoint, _: zap.Request) !void {}
pub fn put(_: *Endpoint, _: zap.Request) !void {}
pub fn delete(_: *Endpoint, _: zap.Request) !void {}
pub fn patch(_: *Endpoint, _: zap.Request) !void {}
pub fn options(_: *Endpoint, _: zap.Request) !void {}
pub fn head(_: *Endpoint, _: zap.Request) !void {}
}; };
pub fn main() !void { pub fn main() !void {

View file

@ -152,13 +152,6 @@ const HtmlEndpoint = struct {
}; };
} }
pub fn post(_: *HtmlEndpoint, _: zap.Request) !void {}
pub fn put(_: *HtmlEndpoint, _: zap.Request) !void {}
pub fn delete(_: *HtmlEndpoint, _: zap.Request) !void {}
pub fn patch(_: *HtmlEndpoint, _: zap.Request) !void {}
pub fn options(_: *HtmlEndpoint, _: zap.Request) !void {}
pub fn head(_: *HtmlEndpoint, _: zap.Request) !void {}
pub fn get(_: *HtmlEndpoint, r: zap.Request) !void { pub fn get(_: *HtmlEndpoint, r: zap.Request) !void {
var buf: [1024]u8 = undefined; var buf: [1024]u8 = undefined;
var userFound: bool = false; var userFound: bool = false;

View file

@ -5,7 +5,11 @@
//! Pass an instance of an Endpoint struct to zap.Endpoint.Listener.register() //! Pass an instance of an Endpoint struct to zap.Endpoint.Listener.register()
//! function to register with the listener. //! function to register with the listener.
//! //!
//! **NOTE**: Endpoints must implement the following "interface": //! **NOTE**: Endpoints can implement the following "interface":
//!
//! Any method handler that's not implemented will be handled automatically:
//! - zap will log it
//! - a response with status code 405 (method not allowed) is sent to the client
//! //!
//! ```zig //! ```zig
//! /// The http request path / slug of the endpoint //! /// The http request path / slug of the endpoint
@ -13,6 +17,7 @@
//! error_strategy: zap.Endpoint.ErrorStrategy, //! error_strategy: zap.Endpoint.ErrorStrategy,
//! //!
//! /// Handlers by request method: //! /// Handlers by request method:
//! /// implement any of the following
//! pub fn get(_: *Self, _: zap.Request) !void {} //! pub fn get(_: *Self, _: zap.Request) !void {}
//! pub fn post(_: *Self, _: zap.Request) !void {} //! pub fn post(_: *Self, _: zap.Request) !void {}
//! pub fn put(_: *Self, _: zap.Request) !void {} //! pub fn put(_: *Self, _: zap.Request) !void {}
@ -44,13 +49,6 @@
//! pub fn get(_: *StopEndpoint, _: zap.Request) !void { //! pub fn get(_: *StopEndpoint, _: zap.Request) !void {
//! zap.stop(); //! zap.stop();
//! } //! }
//!
//! pub fn post(_: *StopEndpoint, _: zap.Request) !void {}
//! pub fn put(_: *StopEndpoint, _: zap.Request) !void {}
//! pub fn delete(_: *StopEndpoint, _: zap.Request) !void {}
//! pub fn patch(_: *StopEndpoint, _: zap.Request) !void {}
//! pub fn options(_: *StopEndpoint, _: zap.Request) !void {}
//! pub fn head(_: *StopEndpoint, _: zap.Request) !void {}
//! }; //! };
//! ``` //! ```
@ -154,10 +152,25 @@ pub fn checkEndpointType(T: type) void {
@compileError("Expected return type of method `" ++ @typeName(T) ++ "." ++ method ++ "` to be !void, got: !" ++ @typeName(ret_info.error_union.payload)); @compileError("Expected return type of method `" ++ @typeName(T) ++ "." ++ method ++ "` to be !void, got: !" ++ @typeName(ret_info.error_union.payload));
} }
} else { } else {
@compileError(@typeName(T) ++ " has no method named `" ++ method ++ "`"); // it is ok not to implement a method handler
// pass
} }
} }
} }
// This can be resolved at comptime so *perhaps it does affect optimiazation
pub fn callHandlerIfExist(comptime fn_name: []const u8, e: anytype, r: Request) anyerror!void {
const EndPointType = @TypeOf(e.*);
if (@hasDecl(EndPointType, fn_name)) {
return @field(EndPointType, fn_name)(e, r);
}
zap.log.debug(
"Unhandled `{s}` {s} request ({s} not implemented in {s})",
.{ r.method orelse "<unknown>", r.path orelse "", fn_name, @typeName(EndPointType) },
);
r.setStatus(.method_not_allowed);
try r.sendBody("405 - method not allowed\r\n");
return;
}
pub const Binder = struct { pub const Binder = struct {
pub const Interface = struct { pub const Interface = struct {
@ -189,13 +202,13 @@ pub const Binder = struct {
pub fn onRequest(self: *Bound, r: zap.Request) !void { pub fn onRequest(self: *Bound, r: zap.Request) !void {
const ret = switch (r.methodAsEnum()) { const ret = switch (r.methodAsEnum()) {
.GET => self.endpoint.*.get(r), .GET => callHandlerIfExist("get", self.endpoint, r),
.POST => self.endpoint.*.post(r), .POST => callHandlerIfExist("post", self.endpoint, r),
.PUT => self.endpoint.*.put(r), .PUT => callHandlerIfExist("put", self.endpoint, r),
.DELETE => self.endpoint.*.delete(r), .DELETE => callHandlerIfExist("delete", self.endpoint, r),
.PATCH => self.endpoint.*.patch(r), .PATCH => callHandlerIfExist("patch", self.endpoint, r),
.OPTIONS => self.endpoint.*.options(r), .OPTIONS => callHandlerIfExist("options", self.endpoint, r),
.HEAD => self.endpoint.*.head(r), .HEAD => callHandlerIfExist("head", self.endpoint, r),
else => error.UnsupportedHtmlRequestMethod, else => error.UnsupportedHtmlRequestMethod,
}; };
if (ret) { if (ret) {
@ -249,8 +262,8 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
/// Authenticates GET requests using the Authenticator. /// Authenticates GET requests using the Authenticator.
pub fn get(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void { pub fn get(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
try switch (self.authenticator.authenticateRequest(&r)) { try switch (self.authenticator.authenticateRequest(&r)) {
.AuthFailed => return self.ep.*.unauthorized(r), .AuthFailed => callHandlerIfExist("unauthorized", self.ep, r),
.AuthOK => self.ep.*.get(r), .AuthOK => callHandlerIfExist("get", self.ep, r),
.Handled => {}, .Handled => {},
}; };
} }
@ -258,8 +271,8 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
/// Authenticates POST requests using the Authenticator. /// Authenticates POST requests using the Authenticator.
pub fn post(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void { pub fn post(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
try switch (self.authenticator.authenticateRequest(&r)) { try switch (self.authenticator.authenticateRequest(&r)) {
.AuthFailed => return self.ep.*.unauthorized(r), .AuthFailed => callHandlerIfExist("unauthorized", self.ep, r),
.AuthOK => self.ep.*.post(r), .AuthOK => callHandlerIfExist("post", self.ep, r),
.Handled => {}, .Handled => {},
}; };
} }
@ -267,8 +280,8 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
/// Authenticates PUT requests using the Authenticator. /// Authenticates PUT requests using the Authenticator.
pub fn put(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void { pub fn put(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
try switch (self.authenticator.authenticateRequest(&r)) { try switch (self.authenticator.authenticateRequest(&r)) {
.AuthFailed => return self.ep.*.unauthorized(r), .AuthFailed => callHandlerIfExist("unauthorized", self.ep, r),
.AuthOK => self.ep.*.put(r), .AuthOK => callHandlerIfExist("put", self.ep, r),
.Handled => {}, .Handled => {},
}; };
} }
@ -276,8 +289,8 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
/// Authenticates DELETE requests using the Authenticator. /// Authenticates DELETE requests using the Authenticator.
pub fn delete(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void { pub fn delete(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
try switch (self.authenticator.authenticateRequest(&r)) { try switch (self.authenticator.authenticateRequest(&r)) {
.AuthFailed => return self.ep.*.unauthorized(r), .AuthFailed => callHandlerIfExist("unauthorized", self.ep, r),
.AuthOK => self.ep.*.delete(r), .AuthOK => callHandlerIfExist("delete", self.ep, r),
.Handled => {}, .Handled => {},
}; };
} }
@ -285,8 +298,8 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
/// Authenticates PATCH requests using the Authenticator. /// Authenticates PATCH requests using the Authenticator.
pub fn patch(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void { pub fn patch(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
try switch (self.authenticator.authenticateRequest(&r)) { try switch (self.authenticator.authenticateRequest(&r)) {
.AuthFailed => return self.ep.*.unauthorized(r), .AuthFailed => callHandlerIfExist("unauthorized", self.ep, r),
.AuthOK => self.ep.*.patch(r), .AuthOK => callHandlerIfExist("patch", self.ep, r),
.Handled => {}, .Handled => {},
}; };
} }
@ -294,8 +307,8 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
/// Authenticates OPTIONS requests using the Authenticator. /// Authenticates OPTIONS requests using the Authenticator.
pub fn options(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void { pub fn options(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
try switch (self.authenticator.authenticateRequest(&r)) { try switch (self.authenticator.authenticateRequest(&r)) {
.AuthFailed => return self.ep.*.unauthorized(r), .AuthFailed => callHandlerIfExist("unauthorized", self.ep, r),
.AuthOK => self.ep.*.put(r), .AuthOK => callHandlerIfExist("options", self.ep, r),
.Handled => {}, .Handled => {},
}; };
} }
@ -303,8 +316,8 @@ pub fn Authenticating(EndpointType: type, Authenticator: type) type {
/// Authenticates HEAD requests using the Authenticator. /// Authenticates HEAD requests using the Authenticator.
pub fn head(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void { pub fn head(self: *AuthenticatingEndpoint, r: zap.Request) anyerror!void {
try switch (self.authenticator.authenticateRequest(&r)) { try switch (self.authenticator.authenticateRequest(&r)) {
.AuthFailed => return self.ep.*.unauthorized(r), .AuthFailed => callHandlerIfExist("unauthorized", self.ep, r),
.AuthOK => self.ep.*.head(r), .AuthOK => callHandlerIfExist("head", self.ep, r),
.Handled => {}, .Handled => {},
}; };
} }

View file

@ -1,5 +1,6 @@
const std = @import("std"); const std = @import("std");
const zap = @import("zap.zig"); const zap = @import("zap.zig");
const callHandlerIfExist = @import("endpoint.zig").callHandlerIfExist;
/// Your middleware components need to contain a handler. /// Your middleware components need to contain a handler.
/// ///
@ -102,16 +103,16 @@ pub fn EndpointHandler(comptime HandlerType: anytype, comptime EndpointType: any
if (!self.options.checkPath or if (!self.options.checkPath or
std.mem.startsWith(u8, r.path orelse "", self.endpoint.path)) std.mem.startsWith(u8, r.path orelse "", self.endpoint.path))
{ {
switch (r.methodAsEnum()) { try switch (r.methodAsEnum()) {
.GET => try self.endpoint.*.get(r), .GET => callHandlerIfExist("get", self.endpoint, r),
.POST => try self.endpoint.*.post(r), .POST => callHandlerIfExist("post", self.endpoint, r),
.PUT => try self.endpoint.*.put(r), .PUT => callHandlerIfExist("put", self.endpoint, r),
.DELETE => try self.endpoint.*.delete(r), .DELETE => callHandlerIfExist("delete", self.endpoint, r),
.PATCH => try self.endpoint.*.patch(r), .PATCH => callHandlerIfExist("patch", self.endpoint, r),
.OPTIONS => try self.endpoint.*.options(r), .OPTIONS => callHandlerIfExist("options", self.endpoint, r),
.HEAD => try self.endpoint.*.head(r), .HEAD => callHandlerIfExist("head", self.endpoint, r),
else => {}, else => {},
} };
} }
// if the request was handled by the endpoint, we may break the chain here // if the request was handled by the endpoint, we may break the chain here

View file

@ -165,12 +165,6 @@ pub const Endpoint = struct {
std.time.sleep(1 * std.time.ns_per_s); std.time.sleep(1 * std.time.ns_per_s);
zap.stop(); zap.stop();
} }
pub fn post(_: *Endpoint, _: zap.Request) !void {}
pub fn put(_: *Endpoint, _: zap.Request) !void {}
pub fn delete(_: *Endpoint, _: zap.Request) !void {}
pub fn patch(_: *Endpoint, _: zap.Request) !void {}
pub fn options(_: *Endpoint, _: zap.Request) !void {}
pub fn head(_: *Endpoint, _: zap.Request) !void {}
}; };
// //
// end of http client code // end of http client code