From 972dc916f7b30d1ce373865e875b8fd9355d07fe Mon Sep 17 00:00:00 2001 From: Anbcodes Date: Thu, 6 Oct 2022 15:57:18 -0400 Subject: [PATCH 1/5] added the ability to specify the type of RouterContext.env --- src/index.ts | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/index.ts b/src/index.ts index 776ce0d..f21f39c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,10 +6,10 @@ * @property {string} url URL String * @property {RouterHandler[]} handlers Array of handler functions */ - export interface Route { + export interface Route { method: string url: string - handlers: RouterHandler[] + handlers: RouterHandler[] } /** @@ -21,8 +21,8 @@ * @property {RouterResponse} res Response Object * @property {RouterNext} next Next Handler */ -export interface RouterContext { - env: any +export interface RouterContext { + env: T req: RouterRequest res: RouterResponse next: RouterNext @@ -103,8 +103,8 @@ export interface RouterNext { * @param {RouterContext} ctx * @returns {Promise | void} */ -export interface RouterHandler { - (ctx: RouterContext): Promise | void +export interface RouterHandler { + (ctx: RouterContext): Promise | void } /** @@ -131,7 +131,7 @@ export interface RouterCorsConfig { * @public * @class */ -export class Router { +export class Router { /** * Router Array @@ -139,7 +139,7 @@ export class Router { * @protected * @type {Route[]} */ - protected routes: Route[] = [] + protected routes: Route[] = [] /** * Global Handlers @@ -147,7 +147,7 @@ export class Router { * @protected * @type {RouterHandler[]} */ - protected globalHandlers: RouterHandler[] = [] + protected globalHandlers: RouterHandler[] = [] /** * Debug Mode @@ -179,7 +179,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public use(...handlers: RouterHandler[]): Router { + public use(...handlers: RouterHandler[]): Router { for (let handler of handlers) { this.globalHandlers.push(handler) } @@ -193,7 +193,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public connect(url: string, ...handlers: RouterHandler[]): Router { + public connect(url: string, ...handlers: RouterHandler[]): Router { return this.register('CONNECT', url, handlers) } @@ -204,7 +204,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public delete(url: string, ...handlers: RouterHandler[]): Router { + public delete(url: string, ...handlers: RouterHandler[]): Router { return this.register('DELETE', url, handlers) } @@ -215,7 +215,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public get(url: string, ...handlers: RouterHandler[]): Router { + public get(url: string, ...handlers: RouterHandler[]): Router { return this.register('GET', url, handlers) } @@ -226,7 +226,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public head(url: string, ...handlers: RouterHandler[]): Router { + public head(url: string, ...handlers: RouterHandler[]): Router { return this.register('HEAD', url, handlers) } @@ -237,7 +237,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public options(url: string, ...handlers: RouterHandler[]): Router { + public options(url: string, ...handlers: RouterHandler[]): Router { return this.register('OPTIONS', url, handlers) } @@ -248,7 +248,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public patch(url: string, ...handlers: RouterHandler[]): Router { + public patch(url: string, ...handlers: RouterHandler[]): Router { return this.register('PATCH', url, handlers) } @@ -259,7 +259,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public post(url: string, ...handlers: RouterHandler[]): Router { + public post(url: string, ...handlers: RouterHandler[]): Router { return this.register('POST', url, handlers) } @@ -270,7 +270,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public put(url: string, ...handlers: RouterHandler[]): Router { + public put(url: string, ...handlers: RouterHandler[]): Router { return this.register('PUT', url, handlers) } @@ -281,7 +281,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public trace(url: string, ...handlers: RouterHandler[]): Router { + public trace(url: string, ...handlers: RouterHandler[]): Router { return this.register('TRACE', url, handlers) } @@ -292,7 +292,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public any(url: string, ...handlers: RouterHandler[]): Router { + public any(url: string, ...handlers: RouterHandler[]): Router { return this.register('*', url, handlers) } @@ -302,7 +302,7 @@ export class Router { * @param {boolean} [state=true] Whether to turn on or off debug mode (default: true) * @returns {Router} */ - public debug(state: boolean = true): Router { + public debug(state: boolean = true): Router { this.debugMode = state return this } @@ -313,7 +313,7 @@ export class Router { * @param {RouterCorsConfig} [config] * @returns {Router} */ - public cors(config?: RouterCorsConfig): Router { + public cors(config?: RouterCorsConfig): Router { this.corsEnabled = true this.corsConfig = { allowOrigin: config?.allowOrigin || '*', @@ -334,7 +334,7 @@ export class Router { * @param {RouterHandler[]} handlers Arrar of handler functions * @returns {Router} */ - private register(method: string, url: string, handlers: RouterHandler[]): Router { + private register(method: string, url: string, handlers: RouterHandler[]): Router { this.routes.push({ method, url, @@ -351,7 +351,7 @@ export class Router { * @param {RouterRequest} request * @returns {Route | undefined} */ - private getRoute(request: RouterRequest): Route | undefined { + private getRoute(request: RouterRequest): Route | undefined { const url = new URL(request.url) const pathArr = url.pathname.split('/').filter(i => i) @@ -388,12 +388,12 @@ export class Router { /** * Handle requests * - * @param {any} env + * @param {T} env * @param {Request} request * @param {any} [extend] * @returns {Promise} */ - public async handle(env: any, request: Request, extend: any = {}): Promise { + public async handle(env: T, request: Request, extend: any = {}): Promise { try { const req: RouterRequest = { ...extend, From e8212b5fa80c5e1dace3965f34885e7588a03f39 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Thu, 24 Nov 2022 16:02:17 +0100 Subject: [PATCH 2/5] rename `T` to `TEnv` --- src/index.ts | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/index.ts b/src/index.ts index f21f39c..0c9fac4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,10 +6,10 @@ * @property {string} url URL String * @property {RouterHandler[]} handlers Array of handler functions */ - export interface Route { + export interface Route { method: string url: string - handlers: RouterHandler[] + handlers: RouterHandler[] } /** @@ -21,8 +21,8 @@ * @property {RouterResponse} res Response Object * @property {RouterNext} next Next Handler */ -export interface RouterContext { - env: T +export interface RouterContext { + env: TEnv req: RouterRequest res: RouterResponse next: RouterNext @@ -103,8 +103,8 @@ export interface RouterNext { * @param {RouterContext} ctx * @returns {Promise | void} */ -export interface RouterHandler { - (ctx: RouterContext): Promise | void +export interface RouterHandler { + (ctx: RouterContext): Promise | void } /** @@ -131,7 +131,7 @@ export interface RouterCorsConfig { * @public * @class */ -export class Router { +export class Router { /** * Router Array @@ -139,7 +139,7 @@ export class Router { * @protected * @type {Route[]} */ - protected routes: Route[] = [] + protected routes: Route[] = [] /** * Global Handlers @@ -147,7 +147,7 @@ export class Router { * @protected * @type {RouterHandler[]} */ - protected globalHandlers: RouterHandler[] = [] + protected globalHandlers: RouterHandler[] = [] /** * Debug Mode @@ -179,7 +179,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public use(...handlers: RouterHandler[]): Router { + public use(...handlers: RouterHandler[]): Router { for (let handler of handlers) { this.globalHandlers.push(handler) } @@ -193,7 +193,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public connect(url: string, ...handlers: RouterHandler[]): Router { + public connect(url: string, ...handlers: RouterHandler[]): Router { return this.register('CONNECT', url, handlers) } @@ -204,7 +204,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public delete(url: string, ...handlers: RouterHandler[]): Router { + public delete(url: string, ...handlers: RouterHandler[]): Router { return this.register('DELETE', url, handlers) } @@ -215,7 +215,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public get(url: string, ...handlers: RouterHandler[]): Router { + public get(url: string, ...handlers: RouterHandler[]): Router { return this.register('GET', url, handlers) } @@ -226,7 +226,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public head(url: string, ...handlers: RouterHandler[]): Router { + public head(url: string, ...handlers: RouterHandler[]): Router { return this.register('HEAD', url, handlers) } @@ -237,7 +237,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public options(url: string, ...handlers: RouterHandler[]): Router { + public options(url: string, ...handlers: RouterHandler[]): Router { return this.register('OPTIONS', url, handlers) } @@ -248,7 +248,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public patch(url: string, ...handlers: RouterHandler[]): Router { + public patch(url: string, ...handlers: RouterHandler[]): Router { return this.register('PATCH', url, handlers) } @@ -259,7 +259,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public post(url: string, ...handlers: RouterHandler[]): Router { + public post(url: string, ...handlers: RouterHandler[]): Router { return this.register('POST', url, handlers) } @@ -270,7 +270,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public put(url: string, ...handlers: RouterHandler[]): Router { + public put(url: string, ...handlers: RouterHandler[]): Router { return this.register('PUT', url, handlers) } @@ -281,7 +281,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public trace(url: string, ...handlers: RouterHandler[]): Router { + public trace(url: string, ...handlers: RouterHandler[]): Router { return this.register('TRACE', url, handlers) } @@ -292,7 +292,7 @@ export class Router { * @param {RouterHandler[]} handlers * @returns {Router} */ - public any(url: string, ...handlers: RouterHandler[]): Router { + public any(url: string, ...handlers: RouterHandler[]): Router { return this.register('*', url, handlers) } @@ -302,7 +302,7 @@ export class Router { * @param {boolean} [state=true] Whether to turn on or off debug mode (default: true) * @returns {Router} */ - public debug(state: boolean = true): Router { + public debug(state: boolean = true): Router { this.debugMode = state return this } @@ -313,7 +313,7 @@ export class Router { * @param {RouterCorsConfig} [config] * @returns {Router} */ - public cors(config?: RouterCorsConfig): Router { + public cors(config?: RouterCorsConfig): Router { this.corsEnabled = true this.corsConfig = { allowOrigin: config?.allowOrigin || '*', @@ -334,7 +334,7 @@ export class Router { * @param {RouterHandler[]} handlers Arrar of handler functions * @returns {Router} */ - private register(method: string, url: string, handlers: RouterHandler[]): Router { + private register(method: string, url: string, handlers: RouterHandler[]): Router { this.routes.push({ method, url, @@ -351,7 +351,7 @@ export class Router { * @param {RouterRequest} request * @returns {Route | undefined} */ - private getRoute(request: RouterRequest): Route | undefined { + private getRoute(request: RouterRequest): Route | undefined { const url = new URL(request.url) const pathArr = url.pathname.split('/').filter(i => i) @@ -388,12 +388,12 @@ export class Router { /** * Handle requests * - * @param {T} env + * @param {TEnv} env * @param {Request} request * @param {any} [extend] * @returns {Promise} */ - public async handle(env: T, request: Request, extend: any = {}): Promise { + public async handle(env: TEnv, request: Request, extend: any = {}): Promise { try { const req: RouterRequest = { ...extend, From 3374b9207592501f177c043900212b6322d96aae Mon Sep 17 00:00:00 2001 From: Toby Date: Thu, 24 Nov 2022 15:50:10 +0100 Subject: [PATCH 3/5] Update README.md --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 63d6096..55d6654 100644 --- a/README.md +++ b/README.md @@ -188,8 +188,7 @@ npm i -D @tsndr/cloudflare-worker-router and replace your `index.ts` / `index.js` with one of the following scripts -
-TypeScript (src/index.ts) +### TypeScript (src/index.ts) ```typescript import { Router } from '@tsndr/cloudflare-worker-router' @@ -215,10 +214,8 @@ export default { } } ``` -
-
-JavaScript (src/index.js) +### JavaScript (src/index.js) ```javascript import { Router } from '@tsndr/cloudflare-worker-router' @@ -233,4 +230,3 @@ export default { } } ``` -
From 01487748af7cd1fe2fdaa348937d69c7eb17074a Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Thu, 24 Nov 2022 17:32:04 +0100 Subject: [PATCH 4/5] update readme --- README.md | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 136 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 55d6654..de26dbf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Cloudflare Workers Router -Cloudflare Workers Router is a super lightweight router (2.30 KiB) with middleware support and **ZERO dependencies** for [Cloudflare Workers](https://workers.cloudflare.com/). +Cloudflare Workers Router is a super lightweight router (1.3K gzipped) with middleware support and **ZERO dependencies** for [Cloudflare Workers](https://workers.cloudflare.com/). When I was trying out Cloudflare Workers I almost immediately noticed how fast it was compared to other serverless offerings. So I wanted to build a full-fledged API to see how it performs doing real work, but since I wasn't able to find a router that suited my needs I created my own. @@ -9,14 +9,106 @@ I worked a lot with [Express.js](https://expressjs.com/) in the past and really ## Contents +- [Features](#features) - [Usage](#usage) - [Reference](#reference) - [Setup](#setup) +## Features + +- ZERO dependencies +- Lightweight (1.3K gzipped) +- Fully written in TypeScript +- Integrated Debug-Mode & CORS helper +- Built specifically around Middlewares + + ## Usage -### Simple Example +### TypeScript Example + +```typescript +import { Router } from '@tsndr/cloudflare-worker-router' + +export interface Env { + // Example binding to KV. Learn more at https://developers.cloudflare.com/workers/runtime-apis/kv/ + // MY_KV_NAMESPACE: KVNamespace; + // + // Example binding to Durable Object. Learn more at https://developers.cloudflare.com/workers/runtime-apis/durable-objects/ + // MY_DURABLE_OBJECT: DurableObjectNamespace; + // + // Example binding to R2. Learn more at https://developers.cloudflare.com/workers/runtime-apis/r2/ + // MY_BUCKET: R2Bucket; +} + + +// Initialize router +const router = new Router() + +// Enabling build in CORS support +router.cors() + +// Register global middleware +router.use(({ req, res, next }) => { + res.headers.set('X-Global-Middlewares', 'true') + next() +}) + +// Simple get +router.get('/user', ({ req, res }) => { + res.body = { + data: { + id: 1, + name: 'John Doe' + } + } +}) + +// Post route with url parameter +router.post('/user/:id', ({ req, res }) => { + + const userId = req.params.id + + // Do stuff... + + if (errorDoingStuff) { + res.status = 400 + res.body = { + error: 'User did stupid stuff!' + } + return + } + + res.status = 204 +}) + +// Delete route using a middleware +router.delete('/user/:id', ({ req, res, next }) => { + + if (!apiTokenIsCorrect) { + res.status = 401 + return + } + + await next() +}, (req, res) => { + + const userId = req.params.id + + // Do stuff... +}) + +// Listen Cloudflare Workers Fetch Event +export default { + async fetch(request, env) { + return router.handle(env, request) + } +} +``` + +
+ JavaScript Example ```javascript import { Router } from '@tsndr/cloudflare-worker-router' @@ -84,6 +176,7 @@ export default { } } ``` +
## Reference @@ -96,6 +189,10 @@ Enable or disable debug mode. Which will return the `error.stack` in case of an #### `state` State is a `boolean` which determines if debug mode should be enabled or not (default: `true`) +Key | Type | Default Value +---------------------- | --------- | ------------- +`state` | `boolean` | `true` + ### `router.use([...handlers])` @@ -106,7 +203,9 @@ Register a global middleware handler. Handler is a `function` which will be called for every request. + #### `ctx` + Object containing `env`, [`req`](#req-object), [`res`](#res-object), `next` @@ -137,6 +236,7 @@ Key | Type | Default Value ### `router.put(url, [...handlers])` ### `router.trace(url, [...handlers])` + #### `url` (string) The URL starting with a `/`. @@ -182,11 +282,19 @@ Key | Type | Description Please follow Cloudflare's [Get started guide](https://developers.cloudflare.com/workers/get-started/guide/) to install wrangler, then install the router using this command: + +#### Initialize Project + +```bash +wrangler init +``` + +Use of TypeScript is strongly encouraged :) + ```bash npm i -D @tsndr/cloudflare-worker-router ``` -and replace your `index.ts` / `index.js` with one of the following scripts ### TypeScript (src/index.ts) @@ -204,7 +312,23 @@ export interface Env { // MY_BUCKET: R2Bucket; } -const router = new Router() +const router = new Router() + +/// Example Route +// +// router.get(/'hi', ({ res }) => { +// res.body = 'Hello World' +//} + + +/// Example Route for splitting into multiple files +// +// const hiHandler: RouteHandler = ({ res }) => { +// res.body = 'Hello World' +// } +// +// router.get('/hi', hiHandler) + // TODO: add your routes here @@ -217,11 +341,18 @@ export default { ### JavaScript (src/index.js) +
+ Consider using TypeScript instead :) + ```javascript import { Router } from '@tsndr/cloudflare-worker-router' const router = new Router() +// router.get(/'hi', ({ res }) => { +// res.body = 'Hello World' +//} + // TODO: add your routes here export default { @@ -230,3 +361,4 @@ export default { } } ``` +
From efd74609f15ffb706b95851a88d5bf85c04a6542 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Thu, 24 Nov 2022 17:36:33 +0100 Subject: [PATCH 5/5] add default any --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 0c9fac4..811e13f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -103,7 +103,7 @@ export interface RouterNext { * @param {RouterContext} ctx * @returns {Promise | void} */ -export interface RouterHandler { +export interface RouterHandler { (ctx: RouterContext): Promise | void }