Comparing version 4.2.7 to 5.0.0
@@ -1,2 +0,2 @@ | ||
import { BodyContent, HeadersJson, HttpHandler } from "../core/HttpMessage"; | ||
import { BodyContent, Handler, HeadersJson, HttpHandler } from '../core/HttpMessage'; | ||
import { Req } from "../core/Req"; | ||
@@ -15,3 +15,3 @@ import { Headers } from "../core/Headers"; | ||
static zipkinClientFrom(incomingReq: Req): HttpHandler; | ||
static gzip(): HttpHandler; | ||
static gzip(): Handler; | ||
} |
@@ -17,3 +17,3 @@ "use strict"; | ||
Client.gzip = function () { | ||
return __1.Filters.GZIP(HttpClient_1.HttpClient); | ||
return __1.Filters.GZIP(__1.asHandler(HttpClient_1.HttpClient)); | ||
}; | ||
@@ -20,0 +20,0 @@ return Client; |
@@ -1,2 +0,2 @@ | ||
import {BodyContent, HeadersJson, HttpHandler} from "../core/HttpMessage"; | ||
import {BodyContent, Handler, HeadersJson, HttpHandler} from '../core/HttpMessage'; | ||
import {Req} from "../core/Req"; | ||
@@ -8,3 +8,3 @@ import {HttpClient} from "./HttpClient"; | ||
import {Uri} from "../core/Uri"; | ||
import {Filters} from ".."; | ||
import {asHandler, Filters} from '..'; | ||
@@ -32,5 +32,5 @@ | ||
static gzip(): HttpHandler { | ||
return Filters.GZIP(HttpClient) | ||
static gzip(): Handler { | ||
return Filters.GZIP(asHandler(HttpClient)) | ||
} | ||
} |
import { Req } from "./Req"; | ||
import { HttpHandler } from "./HttpMessage"; | ||
import { Handler, HttpHandler } from './HttpMessage'; | ||
import { Res } from "./Res"; | ||
import { IdGenerator } from "../zipkin/Zipkin"; | ||
import { Clock } from "./Clock"; | ||
export declare type Filter = (HttpHandler: HttpHandler) => HttpHandler; | ||
export declare type Filter = (handler: Handler | HttpHandler) => Handler; | ||
export declare class Filters { | ||
@@ -8,0 +8,0 @@ static UPGRADE_TO_HTTPS: Filter; |
@@ -39,2 +39,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var HttpMessage_1 = require("./HttpMessage"); | ||
var Res_1 = require("./Res"); | ||
@@ -47,3 +48,3 @@ var Zipkin_1 = require("../zipkin/Zipkin"); | ||
} | ||
Filters.UPGRADE_TO_HTTPS = function (handler) { return function (req) { return __awaiter(_this, void 0, void 0, function () { | ||
Filters.UPGRADE_TO_HTTPS = function (handler) { return HttpMessage_1.asHandler(function (req) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
@@ -54,11 +55,11 @@ if (req.header('x-forwarded-proto') !== 'https') { | ||
else { | ||
return [2 /*return*/, handler(req)]; | ||
return [2 /*return*/, HttpMessage_1.asHandler(handler).handle(req)]; | ||
} | ||
return [2 /*return*/]; | ||
}); | ||
}); }; }; | ||
}); }); }; | ||
Filters.TIMING = timingFilterBuilder(Date); | ||
Filters.DEBUG = debugFilterBuilder(console); | ||
Filters.ZIPKIN = zipkinFilterBuilder(new Zipkin_1.ZipkinIdGenerator()); | ||
Filters.GZIP = function (handler) { return function (req) { return __awaiter(_this, void 0, void 0, function () { | ||
Filters.GZIP = function (handler) { return HttpMessage_1.asHandler(function (req) { return __awaiter(_this, void 0, void 0, function () { | ||
var body; | ||
@@ -70,9 +71,9 @@ return __generator(this, function (_a) { | ||
body = req.bodyStream().pipe(zlib.createGunzip()); | ||
return [4 /*yield*/, handler(req.withBody(body))]; | ||
return [4 /*yield*/, HttpMessage_1.asHandler(handler).handle(req.withBody(body))]; | ||
case 1: return [2 /*return*/, _a.sent()]; | ||
case 2: return [4 /*yield*/, handler(req)]; | ||
case 2: return [4 /*yield*/, HttpMessage_1.asHandler(handler).handle(req)]; | ||
case 3: return [2 /*return*/, _a.sent()]; | ||
} | ||
}); | ||
}); }; }; | ||
}); }); }; | ||
return Filters; | ||
@@ -83,3 +84,3 @@ }()); | ||
var _this = this; | ||
return function (handler) { return function (req) { return __awaiter(_this, void 0, void 0, function () { | ||
return function (handler) { return HttpMessage_1.asHandler(function (req) { return __awaiter(_this, void 0, void 0, function () { | ||
var _a, debug, sampled, isTopLevelRequest, zipkinHeaders, reqWithZipkinHeaders, response; | ||
@@ -101,3 +102,3 @@ return __generator(this, function (_b) { | ||
.replaceHeader(Zipkin_1.ZipkinHeaders.TRACE_ID, zipkinHeaders[Zipkin_1.ZipkinHeaders.TRACE_ID]); | ||
return [4 /*yield*/, handler(reqWithZipkinHeaders)]; | ||
return [4 /*yield*/, HttpMessage_1.asHandler(handler).handle(reqWithZipkinHeaders)]; | ||
case 1: | ||
@@ -122,3 +123,3 @@ response = _b.sent(); | ||
}); | ||
}); }; }; | ||
}); }); }; | ||
} | ||
@@ -128,3 +129,3 @@ exports.zipkinFilterBuilder = zipkinFilterBuilder; | ||
var _this = this; | ||
return function (handler) { return function (req) { return __awaiter(_this, void 0, void 0, function () { | ||
return function (handler) { return HttpMessage_1.asHandler(function (req) { return __awaiter(_this, void 0, void 0, function () { | ||
var start, response, end, total; | ||
@@ -135,3 +136,3 @@ return __generator(this, function (_a) { | ||
start = clock.now(); | ||
return [4 /*yield*/, handler(req)]; | ||
return [4 /*yield*/, HttpMessage_1.asHandler(handler).handle(req)]; | ||
case 1: | ||
@@ -147,3 +148,3 @@ response = _a.sent(); | ||
}); | ||
}); }; }; | ||
}); }); }; | ||
} | ||
@@ -156,7 +157,7 @@ exports.timingFilterBuilder = timingFilterBuilder; | ||
if (messageFrom === void 0) { messageFrom = function (req, res) { return defaultMessageFrom(req, res); }; } | ||
return function (handler) { return function (req) { return __awaiter(_this, void 0, void 0, function () { | ||
return function (handler) { return HttpMessage_1.asHandler(function (req) { return __awaiter(_this, void 0, void 0, function () { | ||
var res; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, handler(req)]; | ||
case 0: return [4 /*yield*/, HttpMessage_1.asHandler(handler).handle(req)]; | ||
case 1: | ||
@@ -168,4 +169,4 @@ res = _a.sent(); | ||
}); | ||
}); }; }; | ||
}); }); }; | ||
} | ||
exports.debugFilterBuilder = debugFilterBuilder; |
import {Req} from "./Req"; | ||
import {HeadersJson, HttpHandler} from "./HttpMessage"; | ||
import {asHandler, Handler, HeadersJson, HttpHandler} from './HttpMessage'; | ||
import {Res} from "./Res"; | ||
@@ -9,12 +9,12 @@ import {IdGenerator, ZipkinHeaders, ZipkinIdGenerator} from "../zipkin/Zipkin"; | ||
export type Filter = (HttpHandler: HttpHandler) => HttpHandler | ||
export type Filter = (handler: Handler | HttpHandler) => Handler | ||
export class Filters { | ||
static UPGRADE_TO_HTTPS: Filter = (handler: HttpHandler) => async (req: Req) => { | ||
static UPGRADE_TO_HTTPS: Filter = (handler: Handler | HttpHandler) => asHandler(async (req: Req) => { | ||
if (req.header('x-forwarded-proto') !== 'https') { | ||
return Res.Redirect(301, `https://${req.uri.hostname()}:${req.uri.port()}${req.uri.path()}`) | ||
} else { | ||
return handler(req); | ||
return asHandler(handler).handle(req); | ||
} | ||
}; | ||
}); | ||
@@ -27,10 +27,10 @@ static TIMING: Filter = timingFilterBuilder(Date); | ||
static GZIP: Filter = (handler: HttpHandler) => async (req: Req) => { | ||
static GZIP: Filter = (handler: Handler | HttpHandler) => asHandler(async (req: Req) => { | ||
if (req.header(Headers.CONTENT_ENCODING) === 'gzip') { | ||
const body = req.bodyStream()!.pipe(zlib.createGunzip()); | ||
return await handler(req.withBody(body)); | ||
return await asHandler(handler).handle(req.withBody(body)); | ||
} else { | ||
return await handler(req); | ||
return await asHandler(handler).handle(req); | ||
} | ||
} | ||
}) | ||
@@ -40,3 +40,3 @@ } | ||
export function zipkinFilterBuilder(generator: IdGenerator): Filter { | ||
return (handler: HttpHandler) => async (req: Req) => { | ||
return (handler: Handler | HttpHandler) => asHandler(async (req: Req) => { | ||
const debug = req.header(ZipkinHeaders.DEBUG); | ||
@@ -54,3 +54,3 @@ const sampled = req.header(ZipkinHeaders.SAMPLED); | ||
.replaceHeader(ZipkinHeaders.TRACE_ID, zipkinHeaders[ZipkinHeaders.TRACE_ID]); | ||
const response = await handler(reqWithZipkinHeaders); | ||
const response = await asHandler(handler).handle(reqWithZipkinHeaders); | ||
if (debug !== undefined && !debug && sampled === '0') return response; | ||
@@ -68,9 +68,9 @@ return Object.keys(zipkinHeaders).reduce((finalResponse: Res, headerKey: string) => { | ||
} , response) | ||
} | ||
}); | ||
} | ||
export function timingFilterBuilder(clock: Clock): Filter { | ||
return (handler: HttpHandler) => async (req: Req) => { | ||
return (handler: Handler | HttpHandler) => asHandler(async (req: Req) => { | ||
const start = clock.now(); | ||
const response = await handler(req); | ||
const response = await asHandler(handler).handle(req); | ||
const end = clock.now(); | ||
@@ -82,3 +82,3 @@ const total = end - start; | ||
.withHeader("End-Time", end.toString()); | ||
}; | ||
}); | ||
@@ -91,7 +91,7 @@ } | ||
export function debugFilterBuilder(out: any, messageFrom: (req: Req, res: Res)=>string = (req, res)=> defaultMessageFrom(req, res)): Filter { | ||
return (handler: HttpHandler) => async (req: Req) => { | ||
const res = await handler(req); | ||
return (handler: Handler | HttpHandler) => asHandler(async (req: Req) => { | ||
const res = await asHandler(handler).handle(req); | ||
out.log(messageFrom(req, res)); | ||
return res; | ||
} | ||
}) | ||
} |
@@ -36,1 +36,5 @@ /// <reference types="node" /> | ||
export declare type HttpHandler = (request: Req) => Promise<Res>; | ||
export interface Handler { | ||
handle(req: Req): Promise<Res>; | ||
} | ||
export declare function asHandler(handler: HttpHandler | Handler): Handler; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function asHandler(handler) { | ||
return (typeof handler) === 'function' ? new /** @class */ (function () { | ||
function class_1() { | ||
} | ||
class_1.prototype.handle = function (req) { | ||
return handler(req); | ||
}; | ||
return class_1; | ||
}()) : handler; | ||
} | ||
exports.asHandler = asHandler; |
@@ -31,1 +31,13 @@ import {Res} from "./Res"; | ||
export type HttpHandler = (request: Req) => Promise<Res> | ||
export interface Handler { | ||
handle(req: Req): Promise<Res>; | ||
} | ||
export function asHandler(handler: HttpHandler | Handler): Handler { | ||
return (typeof handler) === 'function' ? new class implements Handler { | ||
handle(req: Req): Promise<Res> { | ||
return (handler as HttpHandler)(req); | ||
} | ||
} : handler as Handler; | ||
} |
@@ -1,10 +0,10 @@ | ||
import { Res } from "./Res"; | ||
import { HeadersJson, HttpHandler } from "./HttpMessage"; | ||
import { Req } from "./Req"; | ||
import { Filter } from "./Filters"; | ||
import { Http4jsServer } from "../servers/Server"; | ||
import { Res } from './Res'; | ||
import { Handler, HeadersJson, HttpHandler } from './HttpMessage'; | ||
import { Req } from './Req'; | ||
import { Filter } from './Filters'; | ||
import { Http4jsServer } from '../servers/Server'; | ||
export declare type MountedHttpHandler = { | ||
path: string; | ||
method: string; | ||
handler: HttpHandler; | ||
handler: Handler; | ||
headers: HeadersJson; | ||
@@ -29,7 +29,7 @@ name: string; | ||
private readonly unnamedHandlerName; | ||
constructor(method: string, path: string, handler: HttpHandler, headers?: HeadersJson, name?: string); | ||
constructor(method: string, path: string, handler: HttpHandler | Handler, headers?: HeadersJson, name?: string); | ||
withRoutes(routes: Routing): Routing; | ||
withRoute(req: Req, handler: HttpHandler): Routing; | ||
withRoute(req: Req, handler: HttpHandler | Handler): Routing; | ||
withFilter(filter: Filter): Routing; | ||
withHandler(method: string, path: string, handler: HttpHandler, headers?: HeadersJson, name?: string): Routing; | ||
withHandler(method: string, path: string, handler: HttpHandler | Handler, headers?: HeadersJson, name?: string): Routing; | ||
asServer(server?: Http4jsServer): Routing; | ||
@@ -44,9 +44,9 @@ start(): void; | ||
handlerByPath(path: string): MountedHttpHandler | undefined; | ||
withGet(path: string, handler: HttpHandler): Routing; | ||
withPost(path: string, handler: HttpHandler): Routing; | ||
withPut(path: string, handler: HttpHandler): Routing; | ||
withPatch(path: string, handler: HttpHandler): Routing; | ||
withDelete(path: string, handler: HttpHandler): Routing; | ||
withOptions(path: string, handler: HttpHandler): Routing; | ||
withHead(path: string, handler: HttpHandler): Routing; | ||
withGet(path: string, handler: HttpHandler | Handler): Routing; | ||
withPost(path: string, handler: HttpHandler | Handler): Routing; | ||
withPut(path: string, handler: HttpHandler | Handler): Routing; | ||
withPatch(path: string, handler: HttpHandler | Handler): Routing; | ||
withDelete(path: string, handler: HttpHandler | Handler): Routing; | ||
withOptions(path: string, handler: HttpHandler | Handler): Routing; | ||
withHead(path: string, handler: HttpHandler | Handler): Routing; | ||
routes(): DescribingHttpHandler[]; | ||
@@ -57,9 +57,9 @@ private mountedNotFoundHandler; | ||
} | ||
export declare function routes(method: string, path: string, handler: HttpHandler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function route(request: Req, handler: HttpHandler, name?: string): Routing; | ||
export declare function get(path: string, handler: HttpHandler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function post(path: string, handler: HttpHandler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function put(path: string, handler: HttpHandler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function patch(path: string, handler: HttpHandler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function options(path: string, handler: HttpHandler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function head(path: string, handler: HttpHandler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function routes(method: string, path: string, handler: HttpHandler | Handler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function route(request: Req, handler: HttpHandler | Handler, name?: string): Routing; | ||
export declare function get(path: string, handler: HttpHandler | Handler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function post(path: string, handler: HttpHandler | Handler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function put(path: string, handler: HttpHandler | Handler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function patch(path: string, handler: HttpHandler | Handler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function options(path: string, handler: HttpHandler | Handler, headers?: HeadersJson, name?: string): Routing; | ||
export declare function head(path: string, handler: HttpHandler | Handler, headers?: HeadersJson, name?: string): Routing; |
@@ -39,2 +39,3 @@ "use strict"; | ||
var Res_1 = require("./Res"); | ||
var HttpMessage_1 = require("./HttpMessage"); | ||
var HttpClient_1 = require("../client/HttpClient"); | ||
@@ -50,6 +51,6 @@ var NativeServer_1 = require("../servers/NativeServer"); | ||
this.mountedNotFoundHandler = { | ||
path: ".*", | ||
method: ".*", | ||
path: '.*', | ||
method: '.*', | ||
headers: {}, | ||
handler: function (request) { return __awaiter(_this, void 0, void 0, function () { | ||
handler: HttpMessage_1.asHandler(function (request) { return __awaiter(_this, void 0, void 0, function () { | ||
var notFoundBodystring; | ||
@@ -60,11 +61,11 @@ return __generator(this, function (_a) { | ||
}); | ||
}); }, | ||
}); }), | ||
name: 'default not found' | ||
}; | ||
var pathNoTrailingSlash = path.endsWith('/') && path !== "/" ? path.slice(0, -1) : path; | ||
var handlerName = name || handler.name || this.unnamedHandlerName; | ||
var pathNoTrailingSlash = path.endsWith('/') && path !== '/' ? path.slice(0, -1) : path; | ||
var handlerName = name || this.unnamedHandlerName; | ||
this.handlers.push({ | ||
path: pathNoTrailingSlash, | ||
method: method.toUpperCase(), | ||
handler: handler, | ||
handler: HttpMessage_1.asHandler(handler), | ||
headers: headers || {}, | ||
@@ -79,3 +80,9 @@ name: handlerName | ||
Routing.prototype.withRoute = function (req, handler) { | ||
this.handlers.push({ path: req.uri.path(), method: req.method, headers: req.headers, handler: handler, name: 'unnamed' }); | ||
this.handlers.push({ | ||
path: req.uri.path(), | ||
method: req.method, | ||
headers: req.headers, | ||
handler: HttpMessage_1.asHandler(handler), | ||
name: 'unnamed' | ||
}); | ||
return this; | ||
@@ -89,3 +96,3 @@ }; | ||
if (headers === void 0) { headers = {}; } | ||
this.handlers.push({ path: path, method: method, headers: headers, handler: handler, name: name || this.unnamedHandlerName }); | ||
this.handlers.push({ path: path, method: method, headers: headers, handler: HttpMessage_1.asHandler(handler), name: name || this.unnamedHandlerName }); | ||
return this; | ||
@@ -141,3 +148,3 @@ }; | ||
}, matchedHandler.handler); | ||
return filteringHandler(req.withPathParamsFromTemplate(matchedHandler.path)).catch(function () { return Res_1.ResOf(500); }); | ||
return filteringHandler.handle(req.withPathParamsFromTemplate(matchedHandler.path)).catch(function () { return Res_1.ResOf(500); }); | ||
}; | ||
@@ -162,3 +169,3 @@ Routing.prototype.match = function (req) { | ||
return this.handlers.find(function (handler) { | ||
var fuzzyOrExactMatch = handler.path.includes("{") && handler.path != '/' | ||
var fuzzyOrExactMatch = handler.path.includes('{') && handler.path != '/' | ||
? req.uri.templateMatch(handler.path) | ||
@@ -178,21 +185,21 @@ : req.uri.exactMatch(handler.path); | ||
Routing.prototype.withGet = function (path, handler) { | ||
return this.withHandler("GET", path, handler); | ||
return this.withHandler('GET', path, handler); | ||
}; | ||
Routing.prototype.withPost = function (path, handler) { | ||
return this.withHandler("POST", path, handler); | ||
return this.withHandler('POST', path, handler); | ||
}; | ||
Routing.prototype.withPut = function (path, handler) { | ||
return this.withHandler("PUT", path, handler); | ||
return this.withHandler('PUT', path, handler); | ||
}; | ||
Routing.prototype.withPatch = function (path, handler) { | ||
return this.withHandler("PATCH", path, handler); | ||
return this.withHandler('PATCH', path, handler); | ||
}; | ||
Routing.prototype.withDelete = function (path, handler) { | ||
return this.withHandler("DELETE", path, handler); | ||
return this.withHandler('DELETE', path, handler); | ||
}; | ||
Routing.prototype.withOptions = function (path, handler) { | ||
return this.withHandler("OPTIONS", path, handler); | ||
return this.withHandler('OPTIONS', path, handler); | ||
}; | ||
Routing.prototype.withHead = function (path, handler) { | ||
return this.withHandler("HEAD", path, handler); | ||
return this.withHandler('HEAD', path, handler); | ||
}; | ||
@@ -231,3 +238,3 @@ Routing.prototype.routes = function () { | ||
if (headers === void 0) { headers = {}; } | ||
return rootOf("GET", path, handler, headers, name); | ||
return rootOf('GET', path, handler, headers, name); | ||
} | ||
@@ -237,3 +244,3 @@ exports.get = get; | ||
if (headers === void 0) { headers = {}; } | ||
return rootOf("POST", path, handler, headers, name); | ||
return rootOf('POST', path, handler, headers, name); | ||
} | ||
@@ -243,3 +250,3 @@ exports.post = post; | ||
if (headers === void 0) { headers = {}; } | ||
return rootOf("PUT", path, handler, headers, name); | ||
return rootOf('PUT', path, handler, headers, name); | ||
} | ||
@@ -249,3 +256,3 @@ exports.put = put; | ||
if (headers === void 0) { headers = {}; } | ||
return rootOf("PATCH", path, handler, headers, name); | ||
return rootOf('PATCH', path, handler, headers, name); | ||
} | ||
@@ -255,3 +262,3 @@ exports.patch = patch; | ||
if (headers === void 0) { headers = {}; } | ||
return rootOf("OPTIONS", path, handler, headers, name); | ||
return rootOf('OPTIONS', path, handler, headers, name); | ||
} | ||
@@ -261,3 +268,3 @@ exports.options = options; | ||
if (headers === void 0) { headers = {}; } | ||
return rootOf("HEAD", path, handler, headers, name); | ||
return rootOf('HEAD', path, handler, headers, name); | ||
} | ||
@@ -264,0 +271,0 @@ exports.head = head; |
@@ -1,225 +0,232 @@ | ||
import {Res, ResOf} from "./Res"; | ||
import {HeadersJson, HttpHandler} from "./HttpMessage"; | ||
import {Req} from "./Req"; | ||
import {Filter} from "./Filters"; | ||
import {Http4jsServer} from "../servers/Server"; | ||
import {HttpClient} from "../client/HttpClient"; | ||
import {HttpServer} from "../servers/NativeServer"; | ||
import {Res, ResOf} from './Res'; | ||
import {asHandler, Handler, HeadersJson, HttpHandler} from './HttpMessage'; | ||
import {Req} from './Req'; | ||
import {Filter} from './Filters'; | ||
import {Http4jsServer} from '../servers/Server'; | ||
import {HttpClient} from '../client/HttpClient'; | ||
import {HttpServer} from '../servers/NativeServer'; | ||
export type MountedHttpHandler = { path: string, method: string, handler: HttpHandler, headers: HeadersJson, name: string } | ||
export type MountedHttpHandler = { path: string, method: string, handler: Handler, headers: HeadersJson, name: string } | ||
export type DescribingHttpHandler = { path: string, method: string, headers: HeadersJson, name: string } | ||
export type Route = {handler: MountedHttpHandler, filters: Filter[]} | ||
export type Route = { handler: MountedHttpHandler, filters: Filter[] } | ||
export class Routing { | ||
private server?: Http4jsServer; | ||
private handlers: MountedHttpHandler[] = []; | ||
private filters: Array<(httpHandler: HttpHandler) => HttpHandler> = []; | ||
private nestedRouting: Routing[] = []; | ||
private readonly unnamedHandlerName = 'unnamed'; | ||
private server?: Http4jsServer; | ||
private handlers: MountedHttpHandler[] = []; | ||
private filters: Array<(httpHandler: Handler | HttpHandler) => Handler> = []; | ||
private nestedRouting: Routing[] = []; | ||
private readonly unnamedHandlerName = 'unnamed'; | ||
constructor(method: string, | ||
path: string, | ||
handler: HttpHandler, | ||
headers?: HeadersJson, | ||
name?: string) { | ||
const pathNoTrailingSlash = path.endsWith('/') && path !== "/" ? path.slice(0, -1) : path; | ||
const handlerName = name || handler.name || this.unnamedHandlerName; | ||
this.handlers.push({ | ||
path: pathNoTrailingSlash, | ||
method: method.toUpperCase(), | ||
handler, | ||
headers: headers || {}, | ||
name: handlerName}); | ||
} | ||
constructor(method: string, | ||
path: string, | ||
handler: HttpHandler | Handler, | ||
headers?: HeadersJson, | ||
name?: string) { | ||
const pathNoTrailingSlash = path.endsWith('/') && path !== '/' ? path.slice(0, -1) : path; | ||
const handlerName = name || this.unnamedHandlerName; | ||
this.handlers.push({ | ||
path: pathNoTrailingSlash, | ||
method: method.toUpperCase(), | ||
handler: asHandler(handler), | ||
headers: headers || {}, | ||
name: handlerName | ||
}); | ||
} | ||
withRoutes(routes: Routing): Routing { | ||
this.nestedRouting.push(routes); | ||
return this; | ||
} | ||
withRoutes(routes: Routing): Routing { | ||
this.nestedRouting.push(routes); | ||
return this; | ||
} | ||
withRoute(req: Req, handler: HttpHandler): Routing { | ||
this.handlers.push({path: req.uri.path(), method: req.method, headers: req.headers, handler, name: 'unnamed'}); | ||
return this; | ||
} | ||
withRoute(req: Req, handler: HttpHandler | Handler): Routing { | ||
this.handlers.push({ | ||
path: req.uri.path(), | ||
method: req.method, | ||
headers: req.headers, | ||
handler: asHandler(handler), | ||
name: 'unnamed' | ||
}); | ||
return this; | ||
} | ||
withFilter(filter: Filter): Routing { | ||
this.filters.push(filter); | ||
return this; | ||
} | ||
withFilter(filter: Filter): Routing { | ||
this.filters.push(filter); | ||
return this; | ||
} | ||
withHandler(method: string, path: string, handler: HttpHandler, headers: HeadersJson = {}, name?: string): Routing { | ||
this.handlers.push({path, method, headers, handler, name: name || this.unnamedHandlerName}); | ||
return this; | ||
} | ||
withHandler(method: string, path: string, handler: HttpHandler | Handler, headers: HeadersJson = {}, name?: string): Routing { | ||
this.handlers.push({path, method, headers, handler: asHandler(handler), name: name || this.unnamedHandlerName}); | ||
return this; | ||
} | ||
asServer(server: Http4jsServer = HttpServer(3000)): Routing { | ||
this.server = server; | ||
server.registerCatchAllHandler(this); | ||
return this; | ||
} | ||
asServer(server: Http4jsServer = HttpServer(3000)): Routing { | ||
this.server = server; | ||
server.registerCatchAllHandler(this); | ||
return this; | ||
} | ||
start(): void { | ||
if (!this.server) throw new Error('No server...'); | ||
this.server.start(); | ||
} | ||
start(): void { | ||
if (!this.server) throw new Error('No server...'); | ||
this.server.start(); | ||
} | ||
stop(): void { | ||
if (!this.server) throw new Error('No server...'); | ||
this.server.stop(); | ||
} | ||
stop(): void { | ||
if (!this.server) throw new Error('No server...'); | ||
this.server.stop(); | ||
} | ||
async serveE2E(req: Req): Promise<Res> { | ||
if (!this.server) throw new Error('No server...'); | ||
const reqWithFqdn = req.withUri(`http://localhost:${this.server.port}${req.uri.asUriString()}`); | ||
if (!this.server) return ResOf(400, 'Routing does not have a server'); | ||
await this.start(); | ||
const response = await HttpClient(reqWithFqdn); | ||
await this.stop(); | ||
return response; | ||
} | ||
async serveE2E(req: Req): Promise<Res> { | ||
if (!this.server) throw new Error('No server...'); | ||
const reqWithFqdn = req.withUri(`http://localhost:${this.server.port}${req.uri.asUriString()}`); | ||
if (!this.server) return ResOf(400, 'Routing does not have a server'); | ||
await this.start(); | ||
const response = await HttpClient(reqWithFqdn); | ||
await this.stop(); | ||
return response; | ||
} | ||
serve(req: Req): Promise<Res> { | ||
const matchedRoute = this.match(req); | ||
const matchedHandler = matchedRoute ? matchedRoute.handler : this.mountedNotFoundHandler; | ||
const matchedFilters = matchedRoute ? matchedRoute.filters : this.filters; | ||
serve(req: Req): Promise<Res> { | ||
const matchedRoute = this.match(req); | ||
const matchedHandler = matchedRoute ? matchedRoute.handler : this.mountedNotFoundHandler; | ||
const matchedFilters = matchedRoute ? matchedRoute.filters : this.filters; | ||
const filteringHandler = matchedFilters.reduce((prev, next) => { | ||
return next(prev) | ||
}, matchedHandler.handler); | ||
const filteringHandler = matchedFilters.reduce((prev, next) => { | ||
return next(prev) | ||
}, matchedHandler.handler); | ||
return filteringHandler(req.withPathParamsFromTemplate(matchedHandler.path)).catch(() => ResOf(500)); | ||
} | ||
return filteringHandler.handle(req.withPathParamsFromTemplate(matchedHandler.path)).catch(() => ResOf(500)); | ||
} | ||
match(req: Req): Route | undefined { | ||
for (const routing of this.nestedRouting) { | ||
const matchedRouting = routing.match(req); | ||
if (matchedRouting){ | ||
return { | ||
handler: matchedRouting.handler, | ||
filters: [...this.filters, ...matchedRouting.filters] | ||
}; | ||
} | ||
} | ||
const matchThisRouting = this.matchThisRouting(req); | ||
return matchThisRouting | ||
? { handler: matchThisRouting, filters: this.filters } | ||
: undefined; | ||
match(req: Req): Route | undefined { | ||
for (const routing of this.nestedRouting) { | ||
const matchedRouting = routing.match(req); | ||
if (matchedRouting) { | ||
return { | ||
handler: matchedRouting.handler, | ||
filters: [...this.filters, ...matchedRouting.filters] | ||
}; | ||
} | ||
} | ||
const matchThisRouting = this.matchThisRouting(req); | ||
return matchThisRouting | ||
? {handler: matchThisRouting, filters: this.filters} | ||
: undefined; | ||
} | ||
matchThisRouting(req: Req): MountedHttpHandler | undefined { | ||
return this.handlers.find((handler: MountedHttpHandler) => { | ||
const fuzzyOrExactMatch = handler.path.includes("{") && handler.path != '/' | ||
? req.uri.templateMatch(handler.path) | ||
: req.uri.exactMatch(handler.path); | ||
return fuzzyOrExactMatch | ||
&& Routing.methodsMatch(req, handler) | ||
&& Routing.headersMatch(req, handler); | ||
}); | ||
} | ||
matchThisRouting(req: Req): MountedHttpHandler | undefined { | ||
return this.handlers.find((handler: MountedHttpHandler) => { | ||
const fuzzyOrExactMatch = handler.path.includes('{') && handler.path != '/' | ||
? req.uri.templateMatch(handler.path) | ||
: req.uri.exactMatch(handler.path); | ||
return fuzzyOrExactMatch | ||
&& Routing.methodsMatch(req, handler) | ||
&& Routing.headersMatch(req, handler); | ||
}); | ||
} | ||
handlerByName(name: string): MountedHttpHandler | undefined { | ||
return this.handlers.find(it => it.name === name); | ||
} | ||
handlerByName(name: string): MountedHttpHandler | undefined { | ||
return this.handlers.find(it => it.name === name); | ||
} | ||
handlerByPath(path: string): MountedHttpHandler | undefined { | ||
return this.handlers.find(it => it.path === path); | ||
} | ||
handlerByPath(path: string): MountedHttpHandler | undefined { | ||
return this.handlers.find(it => it.path === path); | ||
} | ||
withGet(path: string, handler: HttpHandler): Routing { | ||
return this.withHandler("GET", path, handler); | ||
} | ||
withGet(path: string, handler: HttpHandler | Handler): Routing { | ||
return this.withHandler('GET', path, handler); | ||
} | ||
withPost(path: string, handler: HttpHandler): Routing { | ||
return this.withHandler("POST", path, handler); | ||
} | ||
withPost(path: string, handler: HttpHandler | Handler): Routing { | ||
return this.withHandler('POST', path, handler); | ||
} | ||
withPut(path: string, handler: HttpHandler): Routing { | ||
return this.withHandler("PUT", path, handler); | ||
} | ||
withPut(path: string, handler: HttpHandler | Handler): Routing { | ||
return this.withHandler('PUT', path, handler); | ||
} | ||
withPatch(path: string, handler: HttpHandler): Routing { | ||
return this.withHandler("PATCH", path, handler); | ||
} | ||
withPatch(path: string, handler: HttpHandler | Handler): Routing { | ||
return this.withHandler('PATCH', path, handler); | ||
} | ||
withDelete(path: string, handler: HttpHandler): Routing { | ||
return this.withHandler("DELETE", path, handler); | ||
} | ||
withDelete(path: string, handler: HttpHandler | Handler): Routing { | ||
return this.withHandler('DELETE', path, handler); | ||
} | ||
withOptions(path: string, handler: HttpHandler): Routing { | ||
return this.withHandler("OPTIONS", path, handler); | ||
} | ||
withOptions(path: string, handler: HttpHandler | Handler): Routing { | ||
return this.withHandler('OPTIONS', path, handler); | ||
} | ||
withHead(path: string, handler: HttpHandler): Routing { | ||
return this.withHandler("HEAD", path, handler); | ||
} | ||
withHead(path: string, handler: HttpHandler | Handler): Routing { | ||
return this.withHandler('HEAD', path, handler); | ||
} | ||
routes(): DescribingHttpHandler[] { | ||
const routes = this.handlers.map(handler => ({ | ||
method: handler.method, | ||
path: handler.path, | ||
headers: handler.headers, | ||
name: handler.name, | ||
})); | ||
return this.nestedRouting.reduce((allRoutes: DescribingHttpHandler[], nestedRouting: Routing) => { | ||
return allRoutes.concat(nestedRouting.routes()) | ||
}, []).concat(routes); | ||
} | ||
routes(): DescribingHttpHandler[] { | ||
const routes = this.handlers.map(handler => ({ | ||
method: handler.method, | ||
path: handler.path, | ||
headers: handler.headers, | ||
name: handler.name, | ||
})); | ||
return this.nestedRouting.reduce((allRoutes: DescribingHttpHandler[], nestedRouting: Routing) => { | ||
return allRoutes.concat(nestedRouting.routes()) | ||
}, []).concat(routes); | ||
} | ||
private mountedNotFoundHandler: MountedHttpHandler = { | ||
path: ".*", | ||
method: ".*", | ||
headers: {}, | ||
handler: async (request: Req) => { | ||
const notFoundBodystring = `${request.method} to ${request.uri.asUriString()} did not match routes`; | ||
return new Res(404, notFoundBodystring); | ||
}, | ||
name: 'default not found' | ||
}; | ||
private mountedNotFoundHandler: MountedHttpHandler = { | ||
path: '.*', | ||
method: '.*', | ||
headers: {}, | ||
handler: asHandler(async (request: Req) => { | ||
const notFoundBodystring = `${request.method} to ${request.uri.asUriString()} did not match routes`; | ||
return new Res(404, notFoundBodystring); | ||
}), | ||
name: 'default not found' | ||
}; | ||
private static methodsMatch(req: Req, it: MountedHttpHandler) { | ||
return req.method.match(it.method) != null; | ||
} | ||
private static methodsMatch(req: Req, it: MountedHttpHandler) { | ||
return req.method.match(it.method) != null; | ||
} | ||
private static headersMatch(req: Req, it: MountedHttpHandler): boolean { | ||
return JSON.stringify(req.headers) === JSON.stringify(it.headers) | ||
|| JSON.stringify(it.headers) === JSON.stringify({}); | ||
} | ||
private static headersMatch(req: Req, it: MountedHttpHandler): boolean { | ||
return JSON.stringify(req.headers) === JSON.stringify(it.headers) | ||
|| JSON.stringify(it.headers) === JSON.stringify({}); | ||
} | ||
} | ||
export function routes(method: string, path: string, handler: HttpHandler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf(method, path, handler, headers, name); | ||
export function routes(method: string, path: string, handler: HttpHandler | Handler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf(method, path, handler, headers, name); | ||
} | ||
export function route(request: Req, handler: HttpHandler, name?: string): Routing { | ||
return rootOf(request.method, request.uri.path(), handler, request.headers, name); | ||
export function route(request: Req, handler: HttpHandler | Handler, name?: string): Routing { | ||
return rootOf(request.method, request.uri.path(), handler, request.headers, name); | ||
} | ||
export function get(path: string, handler: HttpHandler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf("GET", path, handler, headers, name); | ||
export function get(path: string, handler: HttpHandler | Handler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf('GET', path, handler, headers, name); | ||
} | ||
export function post(path: string, handler: HttpHandler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf("POST", path, handler, headers, name); | ||
export function post(path: string, handler: HttpHandler | Handler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf('POST', path, handler, headers, name); | ||
} | ||
export function put(path: string, handler: HttpHandler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf("PUT", path, handler, headers, name); | ||
export function put(path: string, handler: HttpHandler | Handler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf('PUT', path, handler, headers, name); | ||
} | ||
export function patch(path: string, handler: HttpHandler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf("PATCH", path, handler, headers, name); | ||
export function patch(path: string, handler: HttpHandler | Handler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf('PATCH', path, handler, headers, name); | ||
} | ||
export function options(path: string, handler: HttpHandler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf("OPTIONS", path, handler, headers, name); | ||
export function options(path: string, handler: HttpHandler | Handler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf('OPTIONS', path, handler, headers, name); | ||
} | ||
export function head(path: string, handler: HttpHandler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf("HEAD", path, handler, headers, name); | ||
export function head(path: string, handler: HttpHandler | Handler, headers: HeadersJson = {}, name?: string): Routing { | ||
return rootOf('HEAD', path, handler, headers, name); | ||
} | ||
function rootOf(method: string, path: string, handler: HttpHandler, headers: HeadersJson = {}, name?: string): Routing { | ||
return new Routing(method, path, handler, headers, name); | ||
function rootOf(method: string, path: string, handler: HttpHandler | Handler, headers: HeadersJson = {}, name?: string): Routing { | ||
return new Routing(method, path, handler, headers, name); | ||
} |
@@ -11,2 +11,3 @@ "use strict"; | ||
__export(require("./core/Headers")); | ||
__export(require("./core/HttpMessage")); | ||
__export(require("./core/Methods")); | ||
@@ -13,0 +14,0 @@ __export(require("./core/Filters")); |
{ | ||
"name": "http4js", | ||
"version": "4.2.7", | ||
"version": "5.0.0", | ||
"description": "A lightweight HTTP toolkit", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -5,3 +5,3 @@ # http4js | ||
# >> [read the docs :)](https://tomshacham.github.io/http4js/) << | ||
# [read the docs :)](https://tomshacham.github.io/http4js/) | ||
@@ -57,2 +57,4 @@ ## Use http4js in your project | ||
### 5.0.0 `move to HttpHandler interface` | ||
### 4.2.6 `fix HttpsClient: post body` | ||
@@ -59,0 +61,0 @@ |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
144528
69
3238
180
4