Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added bun.lockb
Binary file not shown.
37 changes: 37 additions & 0 deletions lib/core/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export function parseURI(uri: string): {
query: string;
filters: { [key: string]: string };
} {
const { pathname: query, searchParams } = new URL(uri);
const filters = Object.fromEntries(searchParams);
return { query, filters };
}

export function match(query: string, template: string): boolean {
const queryEntries = query.split("/").filter(Boolean);
const templateEntries = template.split("/").filter(Boolean);
if (queryEntries.length !== templateEntries.length) return false;
const filteredQueryEntries = queryEntries.filter((entry) =>
isNaN(Number(entry))
);
const filteredTemplateEntries = templateEntries.filter(
(entry) => !entry.startsWith(":")
);
return filteredQueryEntries.join("/") === filteredTemplateEntries.join("/");
}

export function parseParams(
query: string,
template: string
): { [key: string]: string } {
const result: { [key: string]: string } = {};
const queryEntries = query.split("/");
const templateEntries = template.split("/");
for (const [index, entry] of templateEntries.entries()) {
if (!entry.startsWith(":")) continue;
const key = entry.substring(1);
const value = queryEntries[index];
result[key] = value;
}
return result;
}
10 changes: 10 additions & 0 deletions lib/core/http.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type HTTPMethod =
| "GET"
| "POST"
| "PUT"
| "PATCH"
| "DELETE"
| "HEAD"
| "OPTIONS"
| "CONNECT"
| "TRACE";
42 changes: 42 additions & 0 deletions lib/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { match, parseParams, parseURI } from "./core/helpers";
import { HTTPMethod } from "./core/http";
import { Handler } from "./types";

interface Endpoint {
method: HTTPMethod;
template: string;
handler: Handler;
}

export default class Router {
endpoints: Endpoint[] = [];

register(method: HTTPMethod, template: string, handler: Handler) {
this.endpoints.push({ method, template, handler });
}

async handle(request: Request): Promise<Response> {
const { method, url } = request;
const { query, filters } = parseURI(url);
const endpoint = this.endpoints.find(
({ method: endpointMethod, template }) =>
endpointMethod === method && match(query, template)
);
if (!endpoint) return new Response(null, { status: 404 });
const body = await request.json();
const { handler, template } = endpoint;
const params = parseParams(query, template);
let result;
try {
result = await handler({ body, filters, params, request });
} catch (error: unknown) {
const message = (error as Error).message;
return new Response(message, { status: 500 });
}
if (result instanceof Response) return result;
else if (typeof result === "string") return new Response(result);
else if (typeof result === "object")
return new Response(JSON.stringify(result));
else return new Response();
}
}
6 changes: 6 additions & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type Handler = (props: {
params: { [key: string]: string };
filters: { [key: string]: string };
body: object | undefined;
request: Request;
}) => Response | object | string | void;
3 changes: 3 additions & 0 deletions main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Router from "./lib/router";

export const router = new Router();
11 changes: 11 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "@genericst/bun-router",
"module": "main.ts",
"type": "module",
"devDependencies": {
"bun-types": "latest"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}
22 changes: 22 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"compilerOptions": {
"lib": ["ESNext"],
"module": "esnext",
"target": "esnext",
"moduleResolution": "bundler",
"moduleDetection": "force",
"allowImportingTsExtensions": true,
"noEmit": true,
"composite": true,
"strict": true,
"downlevelIteration": true,
"skipLibCheck": true,
"jsx": "preserve",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"types": [
"bun-types"
]
}
}