IOXD_ROUTER(3)libioxd Programmer's ManualIOXD_ROUTER(3)
NAME
ioxd/router.h - groups, endpoints and middleware, and the same as a script.
SYNOPSIS
#include <ioxd.h>
typedef struct ioxd_group ioxd_group;
typedef struct ioxd_endpoint ioxd_endpoint;
ioxd_group *ioxd_group_new(ioxd_group *parent, const char *prefix);
void ioxd_group_use(ioxd_group *group, ioxd_mw mw);
ioxd_endpoint *ioxd_route(ioxd_group *group, const char *method, const char *path, ioxd_handler fn);
void ioxd_endpoint_use(ioxd_endpoint *endpoint, ioxd_mw mw);
static inline ioxd_endpoint *ioxd_get (ioxd_group *g, const char *path, ioxd_handler fn);
static inline ioxd_endpoint *ioxd_post (ioxd_group *g, const char *path, ioxd_handler fn);
static inline ioxd_endpoint *ioxd_put (ioxd_group *g, const char *path, ioxd_handler fn);
static inline ioxd_endpoint *ioxd_patch (ioxd_group *g, const char *path, ioxd_handler fn);
static inline ioxd_endpoint *ioxd_delete(ioxd_group *g, const char *path, ioxd_handler fn);
void ioxd_use(ioxd_mw mw);
void ioxd_default(ioxd_handler fn);
#define IOXD_MAX_MW 16
IOXD_GROUP(prefix, middleware...) { ... }
IOXD_USE(middleware)
IOXD_ROUTE(method, path, handler, middleware...)
IOXD_GET(path, handler, middleware...)
IOXD_POST(path, handler, middleware...)
IOXD_PUT(path, handler, middleware...)
IOXD_PATCH(path, handler, middleware...)
IOXD_DELETE(path, handler, middleware...)
IOXD_DEFAULT(handler)
DESCRIPTION
routing
typedef struct ioxd_group ioxd_group;
typedef struct ioxd_endpoint ioxd_endpoint;
ioxd_group *ioxd_group_new(ioxd_group *parent, const char *prefix);
void ioxd_group_use(ioxd_group *group, ioxd_mw mw);
Endpoints live in groups, and groups nest. A group is a path prefix plus middleware: an endpoint "/users" in a group "/api" under a group "/v1" answers at "/v1/api/users", wrapped by the middleware of every group above it, outermost first, then its own. NULL as the group is the root: no prefix, and the middleware given to ioxd_use. A prefix and what follows it are joined by a '/' when neither side brings one ("/api" and "users" is "/api/users"), and a repeated slash counts once.
Register everything before ioxd_run, from the main thread; methods, paths and prefixes are copied, so temporaries are fine, and anything registered once ioxd_run has started is ignored with a line on stderr. ioxd_run resolves it once: every endpoint's full path into a segment tree and its middleware into one flat chain, which the workers then share read-only. A request costs one walk down the tree - no scan, no regex - and one call through its chain.
- ioxd_group_new
- "/api"; "" for middleware only
- ioxd_group_use
- wraps everything below it
ioxd_endpoint *ioxd_route(ioxd_group *group, const char *method, const char *path, ioxd_handler fn);
void ioxd_endpoint_use(ioxd_endpoint *endpoint, ioxd_mw mw);
An endpoint: method matched exactly, except that HEAD is answered by the GET of a path that has no HEAD of its own; path matched by segment below the group's prefix, with :name captures ("/users/:id") landing in req.route_params. A static segment beats a capture at any depth, and a static path that lacks the method falls through to a capture route that has it. A trailing slash is tolerated. Segments are matched as they arrive on the wire, so an escape in a static segment does not match it, but a captured value is handed over percent-decoded ("/users/a%2Fb" captures "a/b") - raw in the rare case that it does not fit IOXD_ROUTE_ARENA.
- ioxd_endpoint_use
- wraps this one only
static inline ioxd_endpoint *ioxd_get (ioxd_group *g, const char *path, ioxd_handler fn);
static inline ioxd_endpoint *ioxd_post (ioxd_group *g, const char *path, ioxd_handler fn);
static inline ioxd_endpoint *ioxd_put (ioxd_group *g, const char *path, ioxd_handler fn);
static inline ioxd_endpoint *ioxd_patch (ioxd_group *g, const char *path, ioxd_handler fn);
static inline ioxd_endpoint *ioxd_delete(ioxd_group *g, const char *path, ioxd_handler fn);
The verbs, for short: ioxd_get(api, "/users/:id", user).
void ioxd_use(ioxd_mw mw);
Root middleware: every request, the fallbacks included.
void ioxd_default(ioxd_handler fn);
The fallback when no path matches (a built-in 404 by default). A path that matches without the method gets a built-in 405 whose allow header lists every method that path has, on a capture route too. Both run behind the root's middleware only, so that allow header names methods a group's own middleware would otherwise have gated.
the same, as a script
#define IOXD_MAX_MW 16
Registration as a block-structured script: a current group, which the block after IOXD_GROUP sets (the root outside any block), endpoints registered into it, with their own middleware listed after the handler, and IOXD_USE adding middleware to it - so a group's middleware is either listed after its prefix or added with IOXD_USE inside its block. Plain functions underneath, so everything is type-checked; a group's block runs exactly once, and leaving it early - break, return, goto - still closes the group.
IOXD_USE(log);
IOXD_GET("/", home);
IOXD_GROUP("/api", api_header) {
IOXD_GET("/ping", ping);
IOXD_GROUP("/admin", require_token) {
IOXD_GET("/stats", stats, timing);
}
}
- IOXD_MAX_MW
- middleware per group and per endpoint
IOXD_GROUP(prefix, middleware...) { ... }
IOXD_USE(middleware)
IOXD_ROUTE(method, path, handler, middleware...)
IOXD_GET(path, handler, middleware...)
IOXD_POST(path, handler, middleware...)
IOXD_PUT(path, handler, middleware...)
IOXD_PATCH(path, handler, middleware...)
IOXD_DELETE(path, handler, middleware...)
IOXD_DEFAULT(handler)
A break, a return or a goto out of the block skips the loop's increment, so where the compiler has __attribute__((cleanup)) the pop is hung on the block's variable and runs on every way out; a block that ended on its own has already popped and nulled it. Elsewhere the plain form stands, and a group still open at ioxd_run is reported.
EXAMPLES
The same registrations as calls and as a script:
ioxd_group *api = ioxd_group_new(NULL, "/api");
ioxd_group_use(api, auth);
ioxd_get(api, "/users/:id", user); /* GET /api/users/:id, behind auth */
ioxd_endpoint_use(ioxd_post(api, "/users", create), audit);
IOXD_USE(log); /* root middleware: every request */
IOXD_GROUP("/api", auth) {
IOXD_GET ("/users/:id", user);
IOXD_POST("/users", create, audit);
IOXD_GROUP("/admin", require_token) {
IOXD_GET("/stats", stats);
}
}
IOXD_DEFAULT(not_found);
SEE ALSO
ioxd_config(3), ioxd_http(3), ioxd_slice(3), ioxd_json(3), ioxd_pipe(3), ioxd_tls(3), ioxd_examples(7), ioxd(7)
libioxd 0.1.02026-09-09IOXD_ROUTER(3)