jai-server
Version:
Fast , simple and powerful web framework for creating REST APIs for your next project. RESTFul API server
91 lines (90 loc) • 3.63 kB
text/typescript
import * as path from 'path';
import matcher from './matcher';
import RouteObjectMaker from './routeObjectMaker';
import { ErrorHandler500 } from './request/errorHandler';
import { RouteObject, Params, HandlerFunction, ErrorHandlerFunction } from '../types/types';
// Type guards (unchanged)
function isHandlerFunction(handler: unknown): handler is HandlerFunction | ErrorHandlerFunction {
return typeof handler === 'function';
}
function isHandlerObject(handler: any): handler is { stack: RouteObject[] } {
return typeof handler === 'object' && Array.isArray(handler.stack);
}
const Error404 = JSON.stringify({ statusCode: 404, error: 'Not Found', message: 'Not Found' })
function Next(req: any, res: any, i: number, mwLength: number, stack: RouteObject[], contUrl = '/'): HandlerFunction {
return async function NextHandler(nextError: any) {
try {
while (i < mwLength) {
const middleware = stack[i];
if (!middleware) {
i++;
continue;
}
const { url, isUse, method, handler, isErrorHandler } = middleware;
let urlMatched = !url;
let params: Params | boolean = {};
let nextUrl = contUrl;
if (url) {
const urls = Array.isArray(url) ? url : [url];
for (const u of urls) {
if (u == null) {
urlMatched = true;
break;
}
nextUrl = path.join(contUrl, u);
params = matcher(nextUrl, req.url.split('?')[0], !isUse && isHandlerFunction(handler));
if (params) {
urlMatched = true;
break;
}
}
}
const methodMatched = !method || req.method === method;
if (!urlMatched || !methodMatched) {
i++;
continue;
}
if (isHandlerFunction(handler)) {
req.params = params;
const nextFunction = Next(req, res, i + 1, mwLength, stack, contUrl);
if (!nextError && isErrorHandler) {
return await nextFunction(nextError);
}
try {
if (nextError && !isErrorHandler) return await nextFunction(nextError);
// Prepare args based on whether it's an error handler or not
const args = nextError && isErrorHandler
? [nextError, req, res, nextFunction]
: [req, res, nextFunction];
// Use type assertion to resolve the spread operator issue
return await (handler as Function)(...args);
} catch (error: any) {
return await nextFunction(error);
}
} else if (isHandlerObject(handler)) {
const newStack = handler.stack.concat([RouteObjectMaker({
callback: async (err: any, req: any, res: any) =>
await Next(req, res, i + 1, mwLength, stack, contUrl)(err || nextError),
url: null, method: null, isUse: true, isErrorHandler: true
}),
RouteObjectMaker({
callback: async (req: any, res: any) =>
await Next(req, res, i + 1, mwLength, stack, contUrl)(nextError),
url: null, method: null, isUse: true, isErrorHandler: false
})
]);
return await Next(req, res, 0, newStack.length, newStack, isUse ? nextUrl : contUrl)(nextError);
}
i++;
} // loop end
if (nextError) throw nextError;
if (!res.headersSent) {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(Error404);
}
} catch (error: any) {
ErrorHandler500(res, error);
}
};
}
export default Next;