Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add RouterMiddlewareObject #609

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,11 @@ The middleware is processed as a stack, where each middleware function can
control the flow of the response. When the middleware is called, it is passed a
context and reference to the "next" method in the stack.

Middleware can also be an object as long as it has a `handleRequest` method.
Middleware objects can optionally have an `init` function which will be called
when the application starts listening. This makes middleware objects ideal for
encapsulation or delayed initialization.

A more complex example:

```ts
Expand All @@ -197,6 +202,25 @@ app.use(async (ctx, next) => {
ctx.response.headers.set("X-Response-Time", `${ms}ms`);
});

// Counter
class CountingMiddleware implements MiddlewareObject {
#id = 0;
#counter = 0;

init() {
const array = new Uint32Array(1);
crypto.getRandomValues(array);
this.#id = array[0];
}

handleRequest(ctx: Context, next: Next) {
ctx.response.headers.set("X-Response-Count", String(this.#counter++));
ctx.response.headers.set("X-Response-Counter-ID", String(this.#id));
return next();
}
}
app.use(new CountingMiddleware());

// Hello World!
app.use((ctx) => {
ctx.response.body = "Hello World!";
Expand Down Expand Up @@ -758,6 +782,9 @@ await app.listen({ port: 80 });
The `Router` class produces middleware which can be used with an `Application`
to enable routing based on the pathname of the request.

Like regular `Middleware`, router middleware can be an object as long as the
`handleRequest` method is implemented.

### Basic usage

The following example serves up a _RESTful_ service of a map of books, where
Expand Down
30 changes: 29 additions & 1 deletion examples/routingServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,32 @@ function notFound(context: Context) {
`<html><body><h1>404 - Not Found</h1><p>Path <code>${context.request.url}</code> not found.`;
}

class OrdersObject {
#orders = new Set<string>();

handleRequest(context: RouterContext<"/orders">) {
if (context.params["order"]) {
if (this.#orders.has(context.params["order"])) {
context.response.body = `${
context.params["order"]
} is already ordered.`;
} else {
this.#orders.add(context.params["order"]);
context.response.body = `Ordered ${context.params["order"]}.`;
}
} else {
const orders = Array.from(this.#orders.values());
if (orders.length > 0) {
context.response.body = `Orders: ${orders.join(", ")}`;
} else {
context.response.body = "No orders so far.";
}
}
}
}

const orders = new OrdersObject();

const router = new Router();
router
.get("/", (context) => {
Expand Down Expand Up @@ -78,7 +104,9 @@ router
} else {
return notFound(context);
}
});
})
.get("/orders", orders)
.get("/orders/:order", orders);

const app = new Application();

Expand Down
20 changes: 11 additions & 9 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,17 @@ export {
} from "./middleware.ts";
export { Request } from "./request.ts";
export { REDIRECT_BACK, Response } from "./response.ts";
export {
type Route,
type RouteParams,
Router,
type RouterAllowedMethodsOptions,
type RouterContext,
type RouterMiddleware,
type RouterOptions,
type RouterParamMiddleware,
export { Router } from "./router.ts";
export type {
Route,
RouteParams,
RouterAllowedMethodsOptions,
RouterContext,
RouterMiddleware,
RouterMiddlewareObject,
RouterMiddlewareOrMiddlewareObject,
RouterOptions,
RouterParamMiddleware,
} from "./router.ts";
export { send, type SendOptions } from "./send.ts";
/** Utilities for making testing oak servers easier. */
Expand Down
Loading
Loading