Front Controller
The Front Controller is a design pattern that processes all requests to a website using a single handler. The handler decodes the URL and extracts request data to determine which command should process the request. This pattern pairs well with the Intercepting Filter (Decorator) pattern.
References
Fowler, M. (2011). Patterns of Enterprise Application Architecture. Addison-Wesley.
Source Code Listing
code.ts
export abstract class FrontCommand {
protected request: Request;
constructor(request: Request) {
this.request = request;
}
abstract process(): Promise<Response>;
/**
* Helper to build a response by forwarding to a static file (the "view").
*/
protected async forward(pathname: string): Promise<Response> {
// Use Bun.file for optimized file serving.
const file = Bun.file(`${import.meta.dir}/../${pathname}`);
if (await file.exists()) {
return new Response(file);
}
return new Response("Not Found", {status: 404});
}
}
export class ArtistCommand extends FrontCommand {
async process(): Promise<Response> {
const url = new URL(this.request.url);
const artistName = url.searchParams.get("name");
console.log(`Fetching data for artist: ${artistName}`);
// The path is relative to the project root.
return this.forward("views/artist.html");
}
}
export class UnknownCommand extends FrontCommand {
async process(): Promise<Response> {
return new Response("Command not found.", {status: 404});
}
}
type CommandConstructor = new (request: Request) => FrontCommand;
export class FrontController {
public async handle(request: Request): Promise<Response> {
const Command = await this.getCommandClass(request);
const commandInstance = new Command(request);
return commandInstance.process();
}
private async getCommandClass(request: Request): Promise<CommandConstructor> {
const url = new URL(request.url);
const commandName = url.searchParams.get("command");
switch (commandName?.toLowerCase()) {
case "artist":
return ArtistCommand;
default:
return UnknownCommand;
}
}
}
const controller = new FrontController();
const port = 3000;
Bun.serve({
port,
fetch: (request) => controller.handle(request),
});
console.log(`Server running with Bun at http://localhost:${port}`);
Tags
[End]