@velascosoftware/next-api-router
Version:
156 lines (150 loc) • 5.16 kB
JavaScript
import { getReasonPhrase, StatusCodes } from 'http-status-codes';
import { NextResponse } from 'next/server';
import { match } from 'path-to-regexp';
// src/http/routing/ApiRouter.ts
// src/http/utils/metadata.ts
var store = /* @__PURE__ */ new WeakMap();
function getMap(target) {
let m = store.get(target);
if (!m) {
m = /* @__PURE__ */ new Map();
store.set(target, m);
}
return m;
}
function defineMetadata(key, value, target) {
const R = globalThis.Reflect;
if (R && typeof R.defineMetadata === "function") {
R.defineMetadata(key, value, target);
return;
}
getMap(target).set(key, value);
}
function getMetadata(key, target) {
const R = globalThis.Reflect;
if (R && typeof R.getMetadata === "function") {
return R.getMetadata(key, target);
}
return getMap(target).get(key);
}
// src/http/decorators/RoutingMapping.ts
var routesMetadataKey = Symbol("routes");
var routeMiddlewaresKey = Symbol("route_middlewares");
var controllerMiddlewaresKey = Symbol("controller_middlewares");
function RequestMapping(path, method) {
return function(target, propertyKey) {
const routes = getMetadata(routesMetadataKey, target.constructor) || [];
routes.push({
path,
method,
handlerName: propertyKey
});
defineMetadata(routesMetadataKey, routes, target.constructor);
};
}
function Use(...middlewares) {
return function(target, propertyKey) {
const map = getMetadata(routeMiddlewaresKey, target.constructor) || {};
map[propertyKey] = [...map[propertyKey] || [], ...middlewares];
defineMetadata(routeMiddlewaresKey, map, target.constructor);
};
}
function UseController(...middlewares) {
return function(constructor) {
const list = getMetadata(controllerMiddlewaresKey, constructor) || [];
defineMetadata(controllerMiddlewaresKey, [...list, ...middlewares], constructor);
};
}
function getRoutes(target) {
return getMetadata(routesMetadataKey, target.constructor) || [];
}
function getControllerMiddlewares(target) {
return getMetadata(controllerMiddlewaresKey, target.constructor) || [];
}
function getRouteMiddlewares(target) {
return getMetadata(routeMiddlewaresKey, target.constructor) || {};
}
// src/http/routing/ApiRouter.ts
var ApiRouter = class {
routes = [];
basePath = "";
globalErrorHandler = (err, req) => {
const reqPath = req.nextUrl.pathname;
return NextResponse.json({
success: false,
message: getReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR),
path: reqPath
}, { status: StatusCodes.INTERNAL_SERVER_ERROR });
};
constructor(basePath = "", controller) {
this.basePath = basePath;
const controllerRoutes = getRoutes(controller);
const classMiddlewares = getControllerMiddlewares(controller);
const routeMwsMap = getRouteMiddlewares(controller);
for (const route of controllerRoutes) {
const fullPath = `${this.basePath}${route.path}`.replace(/\/+$/, "");
const matcher = match(fullPath, { decode: decodeURIComponent });
const handler = controller[route.handlerName].bind(controller);
const methodMiddlewares = routeMwsMap[route.handlerName] || [];
this.routes.push({
method: route.method,
path: fullPath,
matcher,
handlers: [...classMiddlewares, ...methodMiddlewares, handler]
});
}
}
onError(handler) {
this.globalErrorHandler = handler;
}
async handle(req) {
const reqMethod = req.method?.toUpperCase();
const reqPath = req.nextUrl.pathname.replace(/^\/api/, "");
for (const route of this.routes) {
if (route.method !== reqMethod) continue;
const match = route.matcher(reqPath);
if (match) {
const params = match.params;
const stack = [...route.handlers];
const execute = async (i) => {
if (i < stack.length - 1) {
return stack[i](req, params, () => execute(i + 1));
}
return stack[i](req, params, () => execute(i));
};
try {
return await execute(0);
} catch (err) {
if (route.onError) {
return await route.onError(err, req, params);
}
if (this.globalErrorHandler) {
return await this.globalErrorHandler(err, req, params);
}
return NextResponse.json({
success: false,
message: getReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR)
}, { status: StatusCodes.INTERNAL_SERVER_ERROR });
}
}
}
return NextResponse.json({ sucess: false, message: "Not Found" }, { status: StatusCodes.NOT_FOUND });
}
};
// src/next/createNextRoute.ts
function createNextRoute(controller, basePath = "") {
const router = new ApiRouter(basePath, controller);
const handle = (req) => router.handle(req);
return {
GET: handle,
POST: handle,
PUT: handle,
PATCH: handle,
DELETE: handle,
OPTIONS: handle,
HEAD: handle
};
}
export { ApiRouter, RequestMapping, Use, UseController, createNextRoute, getControllerMiddlewares, getRouteMiddlewares, getRoutes };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map