Group and routes
On this page:
- spider.Group: The routes of one feature under one prefix: what a feature's
routes.build()returns.
spider.Group
pub const Group = struct
A set of routes under one prefix, built by a feature and mounted on the server (server.mount(g) or server.mountFeatures(features)).
pub fn build() spider.Group {
var g = spider.Group.init("/tickets");
_ = g
.defaults(.{ .org_roles = ticket_roles }) // before the routes
.get("", controller.index, .{}) // inherits the defaults
// replaces them:
.post("/:id/approve", controller.approve, .{ .org_roles = admin_roles })
// opts out:
.get("/public-feed", controller.feed, .{ .public = true });
return g;
}
Routes take the same config as server routes (routing/route_config.zig) and plain or extractor handlers (spider.Path / spider.Form / spider.Loaded). A handler that takes the server's decorations is a compile error here.
Fields
router: *Routerprefix: []const u8path_middlewares: [32]PathMiddlewareEntry = undefinedpath_middleware_count: usize = 0has_sse: bool = falsedefault_middlewares: []const MiddlewareFn = &.{}: From defaults(): RBAC middlewares and flags for routes that don't declare their own access rules.default_meta: RouteMeta = .{}use_middlewares: [16]MiddlewareFn = undefined: From use(): run on every route of the group, after its RBAC checks.use_count: usize = 0route_count: usize = 0
Group.init
pub fn init(prefix: []const u8) Group
A new, empty group. prefix goes in front of every path added to it; "" is a group at the root of the site. prefix is not copied. The group's memory is never freed: build groups once, at startup.
Group.defaults
pub fn defaults(self: *Group, comptime config: anytype) *Group
Access rules and flags every route of the group inherits unless the route declares its own .roles / .org_roles / .public / .authenticated / .policy: any one of them replaces all the access rules of the defaults (.quiet_log / .allow_http are overridden one by one). Must come before the group's routes: after one, it panics. A second call replaces the first. Plain sse() routes do not get the defaults.
Group.use
pub fn use(self: *Group, m: MiddlewareFn) *Group
Middleware for every route of this group (applied when the group is mounted, so the order relative to the routes doesn't matter). Runs after the route's RBAC checks. Unlike useAt(), it's tied to the routes, not to a path prefix. At most 16: one more panics.
Group.get
pub fn get(self: *Group, path: []const u8, handler: anytype, comptime config: anytype) *Group
Adds a GET route under the group's prefix: in a group at /posts, "" answers /posts and "/:id" answers /posts/4. Path and config are the ones of Server.get; an empty config (.{}) takes the group's defaults. The handler is fn (*spider.Ctx) !spider.Response, with spider.Path, spider.Form and spider.Loaded parameters if it wants them.
Group.post
pub fn post(self: *Group, path: []const u8, handler: anytype, comptime config: anytype) *Group
Adds a POST route under the group's prefix. Path, handler and config as in get.
Group.put
pub fn put(self: *Group, path: []const u8, handler: anytype, comptime config: anytype) *Group
Adds a PUT route under the group's prefix. Path, handler and config as in get.
Group.delete
pub fn delete(self: *Group, path: []const u8, handler: anytype, comptime config: anytype) *Group
Adds a DELETE route under the group's prefix. Path, handler and config as in get.
Group.patch
pub fn patch(self: *Group, path: []const u8, handler: anytype, comptime config: anytype) *Group
Adds a PATCH route under the group's prefix. Path, handler and config as in get.
Group.head
pub fn head(self: *Group, path: []const u8, handler: anytype, comptime config: anytype) *Group
Adds a HEAD route under the group's prefix. Path, handler and config as in get.
Group.sse
pub fn sse(self: *Group, path: []const u8, comptime handler: fn (*Sse) anyerror!void) *Group
Adds a Server-Sent Events route under the group's prefix. It takes no config and does not get the group's defaults: use sseWith to say who may call it.
Group.sseWith
pub fn sseWith(self: *Group, path: []const u8, comptime handler: fn (*Sse) anyerror!void, comptime config: anytype) *Group
sse() with a route config, like get(): the group's defaults() apply unless the config declares its own access. (sse() takes neither.)
Group.useAt
pub fn useAt(self: *Group, path_suffix: []const u8, m: MiddlewareFn) *Group
Adds a middleware for the group's prefix followed by path_suffix, and everything under that path (whole segments, like Server.useAt). It is tied to the path, not to the routes: use is the one for "every route of this group". At most 32 per group, and 32 in the server the group is mounted on: one more panics.
Related
What the declarations above take or give back, without a name of its own in spider.
RouteMeta
pub const RouteMeta = struct
What a route declares about itself, from its config (.{ .roles, .org_roles, .public, .authenticated, .policy, .quiet_log, .allow_http }, see routing/route_config.zig). Available to middlewares and handlers as c.route(); every field is at its default for a request no route matched.
Fields
public: bool = false: No login needed: auth middlewares (jwks/keycloak/clerk, auth, spider.session) let the request through.quiet_log: bool = false: A successful request isn't logged (heartbeats, polling); 4xx/5xx still are.authenticated: bool = false: Any logged-in user (.authenticated = true): 401 without an identity.allow_http: bool = false: Served over plain HTTP even when the app forces HTTPS (spider.forceHttps) — for clients that can't do TLS.roles: []const []const u8 = &.{}: Informational copy of the RBAC config (the checks themselves are the route's middlewares): shown by the route listing.org_roles: []const []const u8 = &.{}: The route's.org_roles, informational likeroles.policy: ?[]const u8 = null: The name of the route's.policy(spider.policy, spider.resourcePolicy, a policySet's route), if any.
RouteMeta.declaresAccess
pub fn declaresAccess(m: RouteMeta) bool
The route says who may call it: .public, .authenticated, .roles / .org_roles, or .policy.
RouteMeta.writeAccess
pub fn writeAccess(m: RouteMeta, w: *std.Io.Writer) !void
Writes the access column of the route listing: "public", "roles:a,b", "org:a,b", "org:a roles:b", "authenticated", or "-" (nothing declared), followed by " policy:name" when the route has one ("policy:name" alone for a route with only a policy). A route with roles shows them and not "authenticated".