Last active
January 17, 2023 15:43
-
-
Save minheq/c42726309a528dc44ca3cf72992c1f19 to your computer and use it in GitHub Desktop.
Deno minimal router
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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