diff --git a/README.md b/README.md index 2d3d4d6..43f4a85 100644 --- a/README.md +++ b/README.md @@ -170,67 +170,66 @@ Deno.serve( You can use utils for simply configure your HTTP server. -**In Bun:** +### In Deno ```ts -import { router, route } from '@krutoo/fetch-tools'; +import { router } from '@krutoo/fetch-tools'; -Bun.serve({ - port: 8080, - fetch: router( - // handler of GET / - route.get('/', () => new Response('Home page')), - - // handler of PUT /about - route.put('/about', () => new Response('About page')), +const handler = router + .builder() + .get('/', () => new Response('Home page')) + .put('/about', () => new Response('About page')) + .post('/news', () => new Response('News page')) + .all('/stats', () => new Response('Some stats')) + .build(); - // handler of POST /news - route.post('/news', () => new Response('News page')), - - // handler for any method - route('/stats', () => new Response('Some stats')), - ), +await Deno.serve({ + port: 8080, + handler: handler, }); ``` -**In Deno:** +### In Bun ```ts -import { serve } from 'https://deno.land/std@0.182.0/http/server.ts'; -import { router, route } from '@krutoo/fetch-tools'; - -await serve( - router( - route('/', () => new Response('Home page')), - route('/news', () => new Response('News page')), - route('/about', () => new Response('About page')), - ), - { port: 8080 }, -); +import { router } from '@krutoo/fetch-tools'; + +const handler = router + .builder() + .get('/', () => new Response('Home page')) + .put('/about', () => new Response('About page')) + .post('/news', () => new Response('News page')) + .all('/stats', () => new Response('Some stats')) + .build(); + +Bun.serve({ + port: 8080, + fetch: handler, +}); ``` -**In Node.js (node:http or express):** +### In Node.js (`node:http` or `express`) Currently there is no builtin server implementation based on fetch API. Is it possible to use adapter for `node:http` or `express` from [@whatwg-node/server](https://www.npmjs.com/package/@whatwg-node/server). ```ts -import { router, route } from '@krutoo/fetch-tools'; +import { router } from '@krutoo/fetch-tools'; +import { createServer } from 'node:http'; import { createServerAdapter } from '@whatwg-node/server'; -import express from 'express'; -const handler = router( - route('/', () => new Response('Home page')), - route('/news', () => new Response('News page')), - route('/about', () => new Response('About page')), -); +const handler = router + .builder() + .get('/', () => new Response('Home page')) + .put('/about', () => new Response('About page')) + .post('/news', () => new Response('News page')) + .all('/stats', () => new Response('Some stats')) + .build(); -const app = express(); +const server = createServer(createServerAdapter(handler)); -app.get('/greeting', createServerAdapter(handler)); - -app.listen(8080); +server.listen(8080); ``` ### Middleware for servers @@ -238,7 +237,7 @@ app.listen(8080); You can use middleware for server handlers too: ```ts -import { router, route, applyMiddleware } from '@krutoo/fetch-tools'; +import { router, applyMiddleware } from '@krutoo/fetch-tools'; import { log } from '@krutoo/fetch-tools/middleware'; const enhance = applyMiddleware( @@ -247,17 +246,17 @@ const enhance = applyMiddleware( }), ); -const handler = enhance( - router( - route('/', () => new Response('Home page')), - route('/news', () => new Response('News page')), - route('/about', () => new Response('About page')), - ), -); +const handler = router + .builder() + .get('/', () => new Response('Home page')) + .put('/about', () => new Response('About page')) + .post('/news', () => new Response('News page')) + .all('/stats', () => new Response('Some stats')) + .build(); Bun.serve({ port: 8080, - fetch: handler, + fetch: enhance(handler), // just wrap handler to enhancer for apply middleware }); ``` diff --git a/deno.json b/deno.json index d3500b5..e03e362 100644 --- a/deno.json +++ b/deno.json @@ -17,7 +17,7 @@ "./server": "./src/server.ts" }, "lint": { - "exclude": ["npm/"] + "exclude": ["npm/**/*"] }, "publish": { "include": ["LICENSE", "README.md", "src/**/*.ts"], diff --git a/src/configure.ts b/src/configure.ts index 691007a..13a51ba 100644 --- a/src/configure.ts +++ b/src/configure.ts @@ -27,6 +27,10 @@ export function configureFetch( * @returns Enhancer. */ export function applyMiddleware(...list: Array): Enhancer { + if (list.length === 0) { + return handler => handler; + } + return handler => { let result = handler; diff --git a/src/server.ts b/src/server.ts index 6bc9eeb..dc01cc1 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,7 +1,7 @@ import type { Handler } from './types.ts'; interface Route { - is(url: URL, request: Request): boolean; + matches(url: URL, request: Request): boolean; handler: Handler; } @@ -12,7 +12,7 @@ export function router(...routes: Route[]): Handler { const url = new URL(request.url); for (const route of routes) { - if (route.is(url, request)) { + if (route.matches(url, request)) { return route.handler(request); } } @@ -21,16 +21,18 @@ export function router(...routes: Route[]): Handler { }; } +router.builder = builder; + export function route(pattern: RoutePattern, handler: Handler): Route { if (typeof pattern === 'function') { return { - is: pattern, + matches: pattern, handler, }; } return { - is: url => url.pathname === pattern, + matches: url => url.pathname === pattern, handler, }; } @@ -51,14 +53,93 @@ function createRouteFactoryForMethod(method: string) { return (pattern: RoutePattern, handler: Handler): Route => { if (typeof pattern === 'function') { return { - is: (url, req) => isSuitableMethod(req) && pattern(url, req), + matches: (url, req) => isSuitableMethod(req) && pattern(url, req), handler, }; } return { - is: (url, request) => isSuitableMethod(request) && url.pathname === pattern, + matches: (url, request) => isSuitableMethod(request) && url.pathname === pattern, handler, }; }; } + +interface HandlerBuilder { + all(pattern: RoutePattern, handler: Handler): this; + get(pattern: RoutePattern, handler: Handler): this; + post(pattern: RoutePattern, handler: Handler): this; + put(pattern: RoutePattern, handler: Handler): this; + delete(pattern: RoutePattern, handler: Handler): this; + head(pattern: RoutePattern, handler: Handler): this; + options(pattern: RoutePattern, handler: Handler): this; + connect(pattern: RoutePattern, handler: Handler): this; + patch(pattern: RoutePattern, handler: Handler): this; + build(): Handler; +} + +function builder(): HandlerBuilder { + const routeList: Array = []; + + const builder: HandlerBuilder = { + all(pattern, handler) { + routeList.push(route.all(pattern, handler)); + + return builder; + }, + + get(pattern, handler) { + routeList.push(route.get(pattern, handler)); + + return builder; + }, + + post(pattern, handler) { + routeList.push(route.post(pattern, handler)); + + return builder; + }, + + put(pattern, handler) { + routeList.push(route.put(pattern, handler)); + + return builder; + }, + + delete(pattern, handler) { + routeList.push(route.delete(pattern, handler)); + + return builder; + }, + + head(pattern, handler) { + routeList.push(route.head(pattern, handler)); + + return builder; + }, + + options(pattern, handler) { + routeList.push(route.options(pattern, handler)); + + return builder; + }, + + connect(pattern, handler) { + routeList.push(route.connect(pattern, handler)); + + return builder; + }, + + patch(pattern, handler) { + routeList.push(route.patch(pattern, handler)); + + return builder; + }, + + build() { + return router(...routeList); + }, + }; + + return builder; +}