Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
bdfbaa54dc | |||
47fb48d8e0 | |||
90eb7ea55a | |||
6b0d21da60 | |||
cd90a76408 | |||
d4dd306948 | |||
3f12157801 | |||
c0ee40ffd9 | |||
3826058062 | |||
4649021978 | |||
0e9cdcb6eb |
8 changed files with 48 additions and 80 deletions
|
@ -28,7 +28,7 @@ _Zouter_ is an HTTP router library for Zig **zap** HTTP server. It's made to eas
|
|||
|
||||
## Versions
|
||||
|
||||
Zouter 0.1.0 is made for zig 0.13.0 and tested with zap 0.8.0.
|
||||
Zouter 0.2.0 is made for zig 0.14.0 and tested with zap 0.10.1.
|
||||
|
||||
## How to use
|
||||
|
||||
|
@ -37,7 +37,7 @@ Zouter 0.1.0 is made for zig 0.13.0 and tested with zap 0.8.0.
|
|||
In your project directory:
|
||||
|
||||
```shell
|
||||
$ zig fetch --save https://code.zeptotech.net/zedd/zouter/archive/v0.1.0.tar.gz
|
||||
$ zig fetch --save https://code.zeptotech.net/zedd/zouter/archive/v0.2.0.tar.gz
|
||||
```
|
||||
|
||||
In `build.zig`:
|
||||
|
|
40
build.zig
40
build.zig
|
@ -1,15 +1,7 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
// Standard target options allows the person running `zig build` to choose
|
||||
// what target to build for. Here we do not override the defaults, which
|
||||
// means any target is allowed, and the default is native. Other options
|
||||
// for restricting supported target set are available.
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
||||
// Standard optimization options allow the person running `zig build` to select
|
||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
||||
// set a preferred release mode, allowing the user to decide how to optimize.
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
// Load zap dependency.
|
||||
|
@ -19,54 +11,32 @@ pub fn build(b: *std.Build) void {
|
|||
.openssl = false,
|
||||
});
|
||||
|
||||
const lib = b.addSharedLibrary(.{
|
||||
.name = "zouter",
|
||||
.root_source_file = b.path("src/root.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
// This declares intent for the library to be installed into the standard
|
||||
// location when the user invokes the "install" step (the default step when
|
||||
// running `zig build`).
|
||||
b.installArtifact(lib);
|
||||
|
||||
// Add zouter module.
|
||||
const zouter_module = b.addModule("zouter", .{
|
||||
const lib_mod = b.addModule("zouter", .{
|
||||
.root_source_file = b.path("src/root.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
// Add zap dependency.
|
||||
lib.root_module.addImport("zap", zap.module("zap"));
|
||||
zouter_module.addImport("zap", zap.module("zap"));
|
||||
lib_mod.addImport("zap", zap.module("zap"));
|
||||
|
||||
// Creates a step for unit testing. This only builds the test executable
|
||||
// but does not run it.
|
||||
// Add unit tests.
|
||||
const lib_unit_tests = b.addTest(.{
|
||||
.root_source_file = b.path("tests/root.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
// Add zap dependency.
|
||||
lib_unit_tests.root_module.addImport("zap", zap.module("zap"));
|
||||
// Add zouter dependency.
|
||||
lib_unit_tests.root_module.addImport("zouter", zouter_module);
|
||||
|
||||
lib_unit_tests.root_module.addImport("zouter", lib_mod);
|
||||
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
|
||||
|
||||
// Similar to creating the run step earlier, this exposes a `test` step to
|
||||
// the `zig build --help` menu, providing a way for the user to request
|
||||
// running the unit tests.
|
||||
const test_step = b.step("test", "Run unit tests.");
|
||||
test_step.dependOn(&run_lib_unit_tests.step);
|
||||
|
||||
|
||||
// Documentation generation.
|
||||
const install_docs = b.addInstallDirectory(.{
|
||||
.source_dir = lib.getEmittedDocs(),
|
||||
.source_dir = lib_unit_tests.getEmittedDocs(),
|
||||
.install_dir = .prefix,
|
||||
.install_subdir = "docs",
|
||||
});
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
.{
|
||||
.name = "zouter",
|
||||
.version = "0.1.0",
|
||||
.minimum_zig_version = "0.13.0",
|
||||
.name = .zouter,
|
||||
.version = "0.2.0",
|
||||
.minimum_zig_version = "0.14.0",
|
||||
|
||||
.fingerprint = 0xa981704810c376a0,
|
||||
|
||||
.dependencies = .{
|
||||
.zap = .{
|
||||
.url = "https://github.com/zigzap/zap/archive/v0.8.0.tar.gz",
|
||||
.hash = "12209936c3333b53b53edcf453b1670babb9ae8c2197b1ca627c01e72670e20c1a21",
|
||||
.url = "git+https://github.com/zigzap/zap?ref=v0.10.1#8d187310c7ee4f86faa7ef0ecdac0bf747216dea",
|
||||
.hash = "zap-0.9.1-GoeB84M8JACjZKDNq2LA5hB24Z-ZrZ_HUKRXd8qxL2JW",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -14,5 +16,7 @@
|
|||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
"README.md",
|
||||
"LICENSE",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const std = @import("std");
|
||||
const router = @import("router.zig");
|
||||
const route = @import("route.zig");
|
||||
|
||||
|
|
|
@ -28,8 +28,16 @@ pub const RoutingResult = struct {
|
|||
// Move bytes from the end to the beginning of the buffer.
|
||||
std.mem.copyForwards(u8, buffer[0..(decodedValue.len)], buffer[(buffer.len - decodedValue.len)..]);
|
||||
// Resize the buffer to free remaining bytes.
|
||||
_ = self.allocator.resize(buffer, decodedValue.len);
|
||||
buffer = buffer[0..decodedValue.len];
|
||||
if (self.allocator.resize(buffer, decodedValue.len))
|
||||
{ // The buffer could have been resized, change variable length.
|
||||
buffer = buffer[0..decodedValue.len];
|
||||
}
|
||||
else
|
||||
{ // Could not resize the buffer, allocate a new one and free the old one.
|
||||
const originalBuffer = buffer;
|
||||
defer self.allocator.free(originalBuffer);
|
||||
buffer = try self.allocator.dupe(u8, originalBuffer[0..decodedValue.len]);
|
||||
}
|
||||
|
||||
// Add value to params.
|
||||
try self.params.put(try self.allocator.dupe(u8, key), buffer);
|
||||
|
@ -42,18 +50,6 @@ pub const RoutingResult = struct {
|
|||
try self.params.put(try self.allocator.dupe(u8, key), try self.allocator.dupe(u8, value));
|
||||
}
|
||||
|
||||
/// Clone the given result to a new result pointer.
|
||||
pub fn clone(self: *Self) !*Self
|
||||
{
|
||||
const cloned = try Self.init(self.allocator, self.route, self.handler);
|
||||
cloned.params = try self.params.clone();
|
||||
cloned.notFoundHandler = self.notFoundHandler;
|
||||
cloned.preHandlers = try self.preHandlers.clone();
|
||||
cloned.postHandlers = try self.postHandlers.clone();
|
||||
cloned.errorHandlers = try self.errorHandlers.clone();
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/// Initialize a routing result.
|
||||
pub fn init(allocator: std.mem.Allocator, route: *RouteNode, handler: router.RouteHandler) !*Self
|
||||
{
|
||||
|
@ -195,6 +191,8 @@ pub const RouteNode = struct {
|
|||
.handle = definition.handle,
|
||||
.handleNotFound = definition.handleNotFound,
|
||||
.handleError = definition.handleError,
|
||||
.preHandle = definition.preHandle,
|
||||
.postHandle = definition.postHandle,
|
||||
});
|
||||
}
|
||||
else
|
||||
|
@ -203,6 +201,8 @@ pub const RouteNode = struct {
|
|||
childTree.handle = definition.handle;
|
||||
childTree.handleNotFound = definition.handleNotFound;
|
||||
childTree.handleError = definition.handleError;
|
||||
childTree.preHandle = definition.preHandle;
|
||||
childTree.postHandle = definition.postHandle;
|
||||
|
||||
if (definition.children) |children|
|
||||
{ // If there are children, recursively parse them.
|
||||
|
@ -215,17 +215,17 @@ pub const RouteNode = struct {
|
|||
}
|
||||
|
||||
/// Get request handler depending on the request method.
|
||||
pub fn getMethodHandler(self: Self, requestMethod: zap.Method) ?router.RouteHandler
|
||||
pub fn getMethodHandler(self: Self, requestMethod: zap.http.Method) ?router.RouteHandler
|
||||
{
|
||||
if (self.handle) |handle|
|
||||
{ // A handle object is defined, getting the right handler from it.
|
||||
return switch (requestMethod)
|
||||
{ // Return the defined request handler from the request method.
|
||||
zap.Method.GET => handle.get orelse handle.any,
|
||||
zap.Method.POST => handle.post orelse handle.any,
|
||||
zap.Method.PATCH => handle.patch orelse handle.any,
|
||||
zap.Method.PUT => handle.put orelse handle.any,
|
||||
zap.Method.DELETE => handle.delete orelse handle.any,
|
||||
zap.http.Method.GET => handle.get orelse handle.any,
|
||||
zap.http.Method.POST => handle.post orelse handle.any,
|
||||
zap.http.Method.PATCH => handle.patch orelse handle.any,
|
||||
zap.http.Method.PUT => handle.put orelse handle.any,
|
||||
zap.http.Method.DELETE => handle.delete orelse handle.any,
|
||||
else => handle.any,
|
||||
};
|
||||
}
|
||||
|
@ -268,7 +268,7 @@ pub const RouteNode = struct {
|
|||
|
||||
/// Try to find a matching handler in the current route for the given path.
|
||||
/// Return true when a route is matching the request correctly.
|
||||
pub fn match(self: *Self, requestMethod: zap.Method, path: *std.mem.SplitIterator(u8, std.mem.DelimiterType.scalar), result: *RoutingResult) !bool
|
||||
pub fn match(self: *Self, requestMethod: zap.http.Method, path: *std.mem.SplitIterator(u8, std.mem.DelimiterType.scalar), result: *RoutingResult) !bool
|
||||
{
|
||||
// Add pre, post, error and not found handlers, if defined.
|
||||
try self.addHandlers(result);
|
||||
|
@ -276,9 +276,9 @@ pub const RouteNode = struct {
|
|||
if (path.next()) |nextPath|
|
||||
{ // Trying to follow the path by finding a matching children.
|
||||
if (self.staticChildren.get(nextPath)) |child|
|
||||
{ // There is a matching static child, continue to match the path on it.
|
||||
return try child.match(requestMethod, path, result);
|
||||
}
|
||||
{ // There is a matching static child, continue to match the path on it.
|
||||
return try child.match(requestMethod, path, result);
|
||||
}
|
||||
|
||||
const currentIndex = path.index;
|
||||
// No matching static child, trying dynamic children.
|
||||
|
|
|
@ -99,7 +99,7 @@ pub const Router = struct {
|
|||
var errorHandlersIterator = std.mem.reverseIterator(routingResult.errorHandlers.items);
|
||||
while (errorHandlersIterator.next()) |errorHandler|
|
||||
{ // For each error handler, try to run it with the given error.
|
||||
errorHandler(.{
|
||||
errorHandler(MatchedRoute{
|
||||
.route = routingResult.route,
|
||||
.params = routingResult.params,
|
||||
}, request, err) catch {
|
||||
|
@ -121,12 +121,12 @@ pub const Router = struct {
|
|||
self.root.handleError.?(.{}, request, err) catch {};
|
||||
return;
|
||||
};
|
||||
defer routingResult.deinit();
|
||||
// Matching the requested route. Put the result in routingResult pointer.
|
||||
_ = self.root.match(request.methodAsEnum(), &path, routingResult) catch |err| {
|
||||
Self.handleError(request, err, routingResult);
|
||||
return;
|
||||
};
|
||||
defer routingResult.deinit();
|
||||
|
||||
// Try to run matched route handling.
|
||||
Self.runMatchedRouteHandling(routingResult, request)
|
||||
|
@ -138,7 +138,7 @@ pub const Router = struct {
|
|||
fn runMatchedRouteHandling(routingResult: *routeManager.RoutingResult, request: zap.Request) !void
|
||||
{
|
||||
// Initialized route data passed to handlers from the routing result.
|
||||
const routeData = .{
|
||||
const routeData = MatchedRoute{
|
||||
.route = routingResult.route,
|
||||
.params = routingResult.params,
|
||||
};
|
||||
|
@ -165,7 +165,7 @@ pub const Router = struct {
|
|||
}
|
||||
|
||||
/// The on_request function of the HTTP listener.
|
||||
pub fn onRequest(request: zap.Request) void
|
||||
pub fn onRequest(request: zap.Request) anyerror!void
|
||||
{
|
||||
// Call handle of the current router instance.
|
||||
routerInstance.handle(request);
|
||||
|
@ -182,7 +182,7 @@ fn impossible(_: MatchedRoute, _: zap.Request) !void
|
|||
fn defaultNotFoundHandler(_: MatchedRoute, request: zap.Request) !void
|
||||
{
|
||||
try request.setContentType(zap.ContentType.TEXT);
|
||||
request.setStatus(zap.StatusCode.not_found);
|
||||
request.setStatus(zap.http.StatusCode.not_found);
|
||||
try request.sendBody("404: Not Found");
|
||||
}
|
||||
|
||||
|
@ -190,6 +190,6 @@ fn defaultNotFoundHandler(_: MatchedRoute, request: zap.Request) !void
|
|||
fn defaultErrorHandler(_: MatchedRoute, request: zap.Request, _: anyerror) !void
|
||||
{
|
||||
try request.setContentType(zap.ContentType.TEXT);
|
||||
request.setStatus(zap.StatusCode.internal_server_error);
|
||||
request.setStatus(zap.http.StatusCode.internal_server_error);
|
||||
try request.sendBody("500: Internal Server Error");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
const std = @import("std");
|
||||
const zouter = @import("../src/root.zig");
|
||||
|
||||
test {
|
||||
// try std.testing.refAllDecls(zouter);
|
||||
}
|
||||
const zouter = @import("zouter");
|
||||
|
||||
comptime {
|
||||
_ = @import("example.zig");
|
||||
|
|
|
@ -127,11 +127,10 @@ fn runHttp() !void {
|
|||
var listener = zap.HttpListener.init(.{
|
||||
.interface = "127.0.0.1",
|
||||
.port = 8112,
|
||||
.log = false,
|
||||
.log = true,
|
||||
// Add zouter to the listener.
|
||||
.on_request = zouter.Router.onRequest,
|
||||
});
|
||||
zap.enableDebugLog();
|
||||
try listener.listen();
|
||||
|
||||
const notFoundThread = try makeRequestThread(allocator, std.http.Method.GET, "http://127.0.0.1:8112/notfound/query", ¬FoundResponse);
|
||||
|
|
Loading…
Add table
Reference in a new issue