Skip to content

Commit

Permalink
Merge pull request #120 from cosmicboots/endpoint-middleware
Browse files Browse the repository at this point in the history
Create options for EndpointHandler
  • Loading branch information
renerocksai authored Jul 27, 2024
2 parents 11fa66a + 903716b commit e7a6849
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 16 deletions.
16 changes: 7 additions & 9 deletions examples/middleware_with_endpoint/middleware_with_endpoint.zig
Original file line number Diff line number Diff line change
Expand Up @@ -123,19 +123,17 @@ const SessionMiddleWare = struct {
//
// !!!! ENDPOINT !!!
//
// We define an endpoint as we usually would.
// NO ROUTING IS PERFORMED
// as we are just going to wrap it in a bunch of Middleware components
// and therefore NOT using an endpoint listener that would the routing for us
// We define an endpoint as we usually would; however,
// NO ROUTING IS PERFORMED BY DEFAULT!
//
// Hence, the endpoint should check r.path in its on_request to check wether
// it is adressed or not.
// This can be changed using the EndpointHandlerOptions passed into the
// EndpointHandler.init() method.
//
// N.B. the EndpointHandler checks if the endpoint turned the request into
// "finished" state, e.g. by sending anything. If the endpoint didn't finish the
// request, the EndpointHandler will pass the request on to the next handler in
// the chain if there is one. See also the EndpointHandler's `breakOnFinish`
// parameter.
// the chain if there is one. See also the EndpointHandlerOptions's
// `breakOnFinish` parameter.
//
const HtmlEndpoint = struct {
ep: zap.Endpoint = undefined,
Expand Down Expand Up @@ -210,7 +208,7 @@ pub fn main() !void {
var htmlHandler = zap.Middleware.EndpointHandler(Handler, Context).init(
htmlEndpoint.endpoint(), // the endpoint
null, // no other handler (we are the last in the chain)
true, // break on finish. See EndpointHandler for this. Not applicable here.
.{}, // We can set custom EndpointHandlerOptions here
);

// we wrap it in the session Middleware component
Expand Down
33 changes: 26 additions & 7 deletions src/middleware.zig
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,38 @@ pub fn Handler(comptime ContextType: anytype) type {
};
}

/// 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,
};

/// A convenience handler for artibrary zap.Endpoint
pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anytype) type {
return struct {
handler: HandlerType,
endpoint: *zap.Endpoint,
breakOnFinish: bool,
options: EndpointHandlerOptions,

const Self = @This();

/// Create an endpointhandler from an endpoint and pass in the next (other) handler in the chain.
/// If `breakOnFinish` is `true`, the handler will stop handing requests down the chain if
/// the endpoint processed the request.
pub fn init(endpoint: *zap.Endpoint, other: ?*HandlerType, breakOnFinish: bool) Self {
///
/// By default no routing is performed on requests. This behavior can be changed by setting
/// `checkPath` in the provided options.
///
/// If the `breakOnFinish` option is `true`, the handler will stop handing requests down the chain
/// if the endpoint processed the request.
pub fn init(endpoint: *zap.Endpoint, other: ?*HandlerType, options: EndpointHandlerOptions) Self {
return .{
.handler = HandlerType.init(onRequest, other),
.endpoint = endpoint,
.breakOnFinish = breakOnFinish,
.options = options,
};
}

Expand All @@ -84,10 +99,14 @@ pub fn EndpointHandler(comptime HandlerType: anytype, comptime ContextType: anyt
pub fn onRequest(handler: *HandlerType, r: zap.Request, context: *ContextType) bool {
const self: *Self = @fieldParentPtr("handler", handler);
r.setUserContext(context);
self.endpoint.onRequest(r);
if (!self.options.checkPath or
std.mem.startsWith(u8, r.path orelse "", self.endpoint.settings.path))
{
self.endpoint.onRequest(r);
}

// if the request was handled by the endpoint, we may break the chain here
if (r.isFinished() and self.breakOnFinish) {
if (r.isFinished() and self.options.breakOnFinish) {
return true;
}
return self.handler.handleOther(r, context);
Expand Down

0 comments on commit e7a6849

Please sign in to comment.