Skip to content

Instantly share code, notes, and snippets.

@minheq
Last active January 17, 2023 15:43
Show Gist options
  • Save minheq/c42726309a528dc44ca3cf72992c1f19 to your computer and use it in GitHub Desktop.
Save minheq/c42726309a528dc44ca3cf72992c1f19 to your computer and use it in GitHub Desktop.
Deno minimal router
import { serve, ServeInit } from "https://deno.land/std@0.171.0/http/server.ts";
export type PathParams = Record<string, string> | undefined;
export type CallbackHandler<T> = (
request: Request,
params: PathParams,
ctx: T
) => Promise<Response>;
type HttpMethod =
| "GET"
| "HEAD"
| "POST"
| "PUT"
| "DELETE"
| "OPTIONS"
| "TRACE"
| "PATCH";
interface RouteHandler<T> {
pattern: URLPattern;
handler: CallbackHandler<T>;
}
type CreateContext<T> = (req: Request) => Promise<T>;
/**
* # Usage
*
* export const app = new Router<RequestContext>({ context: createContext });
*
* app.add("GET", "/organizations/:id", getOrganizationHandler);
* app.add("POST", "/organizations", createOrganizationHandler);
*/
export class Router<T> {
private createContext: CreateContext<T>;
constructor({ context }: { context: CreateContext<T> }) {
this.createContext = context;
}
private routes: Record<HttpMethod, Array<RouteHandler<T>>> = {
GET: [],
HEAD: [],
POST: [],
PUT: [],
DELETE: [],
OPTIONS: [],
TRACE: [],
PATCH: [],
};
add(method: HttpMethod, pathname: string, handler: CallbackHandler<T>) {
this.routes[method].push({
pattern: new URLPattern({ pathname }),
handler,
});
}
async serve(init?: ServeInit) {
await serve(this.handler, init);
}
async handler(req: Request) {
const route = this.match(req);
if (!route) {
return new Response(JSON.stringify({ message: "Route not found." }), {
status: 404,
});
}
const params: PathParams = route.pattern.exec(req.url)?.pathname.groups;
try {
const response = await route.handler(
req,
params,
await this.createContext(req)
);
return response;
} catch (error) {
const response = new Response(
JSON.stringify({ message: error.message }),
{
status: 500,
}
);
return response;
}
}
private match(req: Request): RouteHandler<T> | null {
for (const r of this.routes[req.method as HttpMethod]) {
if (r.pattern.test(req.url)) {
return r;
}
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment