mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 15:14:08 +00:00
Improved & generalized checkEndpoint functions
E.g. return type's error set does not need to be `anyerror` anymore.
This commit is contained in:
parent
793423b7c2
commit
cc6d55fbf7
5 changed files with 115 additions and 17 deletions
|
@ -14,14 +14,14 @@ pub fn init(path: []const u8) StopEndpoint {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(e: *StopEndpoint, r: zap.Request) anyerror!void {
|
pub fn get(e: *StopEndpoint, r: zap.Request) !void {
|
||||||
_ = e;
|
_ = e;
|
||||||
_ = r;
|
_ = r;
|
||||||
zap.stop();
|
zap.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post(_: *StopEndpoint, _: zap.Request) anyerror!void {}
|
pub fn post(_: *StopEndpoint, _: zap.Request) !void {}
|
||||||
pub fn put(_: *StopEndpoint, _: zap.Request) anyerror!void {}
|
pub fn put(_: *StopEndpoint, _: zap.Request) !void {}
|
||||||
pub fn delete(_: *StopEndpoint, _: zap.Request) anyerror!void {}
|
pub fn delete(_: *StopEndpoint, _: zap.Request) !void {}
|
||||||
pub fn patch(_: *StopEndpoint, _: zap.Request) anyerror!void {}
|
pub fn patch(_: *StopEndpoint, _: zap.Request) !void {}
|
||||||
pub fn options(_: *StopEndpoint, _: zap.Request) anyerror!void {}
|
pub fn options(_: *StopEndpoint, _: zap.Request) !void {}
|
||||||
|
|
|
@ -43,8 +43,9 @@ fn userIdFromPath(self: *UserWeb, path: []const u8) ?usize {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put(_: *UserWeb, _: zap.Request) anyerror!void {}
|
pub fn put(_: *UserWeb, _: zap.Request) !void {}
|
||||||
pub fn get(self: *UserWeb, r: zap.Request) anyerror!void {
|
|
||||||
|
pub fn get(self: *UserWeb, r: zap.Request) !void {
|
||||||
if (r.path) |path| {
|
if (r.path) |path| {
|
||||||
// /users
|
// /users
|
||||||
if (path.len == self.path.len) {
|
if (path.len == self.path.len) {
|
||||||
|
@ -69,7 +70,7 @@ fn listUsers(self: *UserWeb, r: zap.Request) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post(self: *UserWeb, r: zap.Request) anyerror!void {
|
pub fn post(self: *UserWeb, r: zap.Request) !void {
|
||||||
if (r.body) |body| {
|
if (r.body) |body| {
|
||||||
const maybe_user: ?std.json.Parsed(User) = std.json.parseFromSlice(User, self.alloc, body, .{}) catch null;
|
const maybe_user: ?std.json.Parsed(User) = std.json.parseFromSlice(User, self.alloc, body, .{}) catch null;
|
||||||
if (maybe_user) |u| {
|
if (maybe_user) |u| {
|
||||||
|
@ -86,7 +87,7 @@ pub fn post(self: *UserWeb, r: zap.Request) anyerror!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn patch(self: *UserWeb, r: zap.Request) anyerror!void {
|
pub fn patch(self: *UserWeb, r: zap.Request) !void {
|
||||||
if (r.path) |path| {
|
if (r.path) |path| {
|
||||||
if (self.userIdFromPath(path)) |id| {
|
if (self.userIdFromPath(path)) |id| {
|
||||||
if (self._users.get(id)) |_| {
|
if (self._users.get(id)) |_| {
|
||||||
|
@ -109,7 +110,7 @@ pub fn patch(self: *UserWeb, r: zap.Request) anyerror!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(self: *UserWeb, r: zap.Request) anyerror!void {
|
pub fn delete(self: *UserWeb, r: zap.Request) !void {
|
||||||
if (r.path) |path| {
|
if (r.path) |path| {
|
||||||
if (self.userIdFromPath(path)) |id| {
|
if (self.userIdFromPath(path)) |id| {
|
||||||
var jsonbuf: [128]u8 = undefined;
|
var jsonbuf: [128]u8 = undefined;
|
||||||
|
@ -124,7 +125,7 @@ pub fn delete(self: *UserWeb, r: zap.Request) anyerror!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn options(_: *UserWeb, r: zap.Request) anyerror!void {
|
pub fn options(_: *UserWeb, r: zap.Request) !void {
|
||||||
try r.setHeader("Access-Control-Allow-Origin", "*");
|
try r.setHeader("Access-Control-Allow-Origin", "*");
|
||||||
try r.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
|
try r.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
|
||||||
r.setStatus(zap.http.StatusCode.no_content);
|
r.setStatus(zap.http.StatusCode.no_content);
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//!
|
||||||
|
//! Part of the Zap examples.
|
||||||
|
//!
|
||||||
|
//! Build me with `zig build endpoint_auth`.
|
||||||
|
//! Run me with `zig build run-endpoint_auth`.
|
||||||
|
//!
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const zap = @import("zap");
|
const zap = @import("zap");
|
||||||
|
|
||||||
|
|
50
src/App.zig
50
src/App.zig
|
@ -153,12 +153,56 @@ pub fn Create(comptime Context: type) type {
|
||||||
"patch",
|
"patch",
|
||||||
"options",
|
"options",
|
||||||
};
|
};
|
||||||
|
const params_to_check = [_]type{
|
||||||
|
*T,
|
||||||
|
Allocator,
|
||||||
|
*Context,
|
||||||
|
Request,
|
||||||
|
};
|
||||||
inline for (methods_to_check) |method| {
|
inline for (methods_to_check) |method| {
|
||||||
if (@hasDecl(T, method)) {
|
if (@hasDecl(T, method)) {
|
||||||
const Method = @TypeOf(@field(T, method));
|
const Method = @TypeOf(@field(T, method));
|
||||||
const Expected = fn (_: *T, _: Allocator, _: *Context, _: Request) anyerror!void;
|
const method_info = @typeInfo(Method);
|
||||||
if (Method != Expected) {
|
if (method_info != .@"fn") {
|
||||||
@compileError(method ++ " method of " ++ @typeName(T) ++ " has wrong type:\n" ++ @typeName(Method) ++ "\nexpected:\n" ++ @typeName(Expected));
|
@compileError("Expected `" ++ @typeName(T) ++ "." ++ method ++ "` to be a request handler method, got: " ++ @typeName(Method));
|
||||||
|
}
|
||||||
|
|
||||||
|
// now check parameters
|
||||||
|
const params = method_info.@"fn".params;
|
||||||
|
if (params.len != params_to_check.len) {
|
||||||
|
@compileError(std.fmt.comptimePrint(
|
||||||
|
"Expected method `{s}.{s}` to have {d} parameters, got {d}",
|
||||||
|
.{
|
||||||
|
@typeName(T),
|
||||||
|
method,
|
||||||
|
params_to_check.len,
|
||||||
|
params.len,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline for (params_to_check, 0..) |param_type_expected, i| {
|
||||||
|
if (params[i].type.? != param_type_expected) {
|
||||||
|
@compileError(std.fmt.comptimePrint(
|
||||||
|
"Expected parameter {d} of method {s}.{s} to be {s}, got {s}",
|
||||||
|
.{
|
||||||
|
i + 1,
|
||||||
|
@typeName(T),
|
||||||
|
method,
|
||||||
|
@typeName(param_type_expected),
|
||||||
|
@typeName(params[i].type.?),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ret_type = method_info.@"fn".return_type.?;
|
||||||
|
const ret_info = @typeInfo(ret_type);
|
||||||
|
if (ret_info != .error_union) {
|
||||||
|
@compileError("Expected return type of method `" ++ @typeName(T) ++ "." ++ method ++ "` to be !void, got: " ++ @typeName(ret_type));
|
||||||
|
}
|
||||||
|
if (ret_info.error_union.payload != void) {
|
||||||
|
@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 ++ "`");
|
@compileError(@typeName(T) ++ " has no method named `" ++ method ++ "`");
|
||||||
|
|
|
@ -95,10 +95,57 @@ pub fn checkEndpointType(T: type) void {
|
||||||
"patch",
|
"patch",
|
||||||
"options",
|
"options",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const params_to_check = [_]type{
|
||||||
|
*T,
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
inline for (methods_to_check) |method| {
|
inline for (methods_to_check) |method| {
|
||||||
if (@hasDecl(T, method)) {
|
if (@hasDecl(T, method)) {
|
||||||
if (@TypeOf(@field(T, method)) != fn (_: *T, _: Request) anyerror!void) {
|
const Method = @TypeOf(@field(T, method));
|
||||||
@compileError(method ++ " method of " ++ @typeName(T) ++ " has wrong type:\n" ++ @typeName(@TypeOf(T.get)) ++ "\nexpected:\n" ++ @typeName(fn (_: *T, _: Request) anyerror!void));
|
const method_info = @typeInfo(Method);
|
||||||
|
if (method_info != .@"fn") {
|
||||||
|
@compileError("Expected `" ++ @typeName(T) ++ "." ++ method ++ "` to be a request handler method, got: " ++ @typeName(Method));
|
||||||
|
}
|
||||||
|
|
||||||
|
// now check parameters
|
||||||
|
const params = method_info.@"fn".params;
|
||||||
|
if (params.len != params_to_check.len) {
|
||||||
|
@compileError(std.fmt.comptimePrint(
|
||||||
|
"Expected method `{s}.{s}` to have {d} parameters, got {d}",
|
||||||
|
.{
|
||||||
|
@typeName(T),
|
||||||
|
method,
|
||||||
|
params_to_check.len,
|
||||||
|
params.len,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline for (params_to_check, 0..) |param_type_expected, i| {
|
||||||
|
if (params[i].type.? != param_type_expected) {
|
||||||
|
@compileError(std.fmt.comptimePrint(
|
||||||
|
"Expected parameter {d} of method {s}.{s} to be {s}, got {s}",
|
||||||
|
.{
|
||||||
|
i + 1,
|
||||||
|
@typeName(T),
|
||||||
|
method,
|
||||||
|
@typeName(param_type_expected),
|
||||||
|
@typeName(params[i].type.?),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check return type
|
||||||
|
const ret_type = method_info.@"fn".return_type.?;
|
||||||
|
const ret_info = @typeInfo(ret_type);
|
||||||
|
if (ret_info != .error_union) {
|
||||||
|
@compileError("Expected return type of method `" ++ @typeName(T) ++ "." ++ method ++ "` to be !void, got: " ++ @typeName(ret_type));
|
||||||
|
}
|
||||||
|
if (ret_info.error_union.payload != void) {
|
||||||
|
@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 ++ "`");
|
@compileError(@typeName(T) ++ " has no method named `" ++ method ++ "`");
|
||||||
|
|
Loading…
Add table
Reference in a new issue