UNPKG

faker-api

Version:

A fully customizible rest api faking package that allows you to mock , clone and fake Rest API with fake yet realistic data

335 lines 14.6 kB
"use strict"; /* tslint:disable:variable-name*/ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FakerServer = void 0; var express_1 = require("express"); var express_2 = __importDefault(require("express")); var models_1 = require("../models"); var logger_1 = require("./logger"); var path_1 = require("./path"); var transformers_1 = require("../transformers"); var router_1 = require("../router"); /** * This is the class that is been used to instantiate the api faker server instance * */ var FakerServer = /** @class */ (function () { function FakerServer(serverPath, expressInstance) { if (serverPath === void 0) { serverPath = ""; } var _this = this; /** * @type string specific the route the server would be running on */ this.serverPath = ""; this.appPassed = false; // Single method handler , handlers can be a function or a model this.methodRequestHanders = new Map(); this.routerMaps = new Map(); this.__internlRouterRoot = "/___internalRouter"; var path = serverPath === null || serverPath === void 0 ? void 0 : serverPath.trim(); if (expressInstance) { this.appPassed = true; this.expressApp = expressInstance; } else { this.expressApp = (0, express_2.default)(); } this.__internalRouter = new router_1.Router(); this.route(this.__internlRouterRoot, this.__internalRouter); // Request the handler for all request this.expressRouter = (0, express_1.Router)(); this.expressApp.use(this.serverPath, this.expressRouter); if (path === "" || !path) { this.expressRouter.all("*", function (req, res) { _this.onNewRequest(req, res); }); } else { var pattern = RegExp("^\/+"); var p = this.serverPath.replace(pattern, ""); p = "/" + p; this.serverPath = p; this.expressRouter.all(p, function (req, res) { _this.onNewRequest(req, res); }); } } /** * Returns an instance of a FakerServer with the given express application instance * * @param expressInstance An express application instance * @param path [string="/api"] The path the Faker Server will be running on, on the express application * @returns An instance of FakerServer * */ FakerServer.from = function (expressInstance, path) { if (path === void 0) { path = "/api"; } return new FakerServer(path, expressInstance); }; /** * Start the faker server. * @remark This method should be called if the faker server instance was created / instantiated without passing an express application instance. * @param port - The port the faker server internally created express application instance will run on */ FakerServer.prototype.run = function (port) { var _this = this; if (port === void 0) { port = 8800; } if (this.appPassed) { (0, logger_1.logMessage)("Message an instance of Express app was pass to the constructor, no need to call run, the Faker server will start the moment the Express app starts", "warning"); return; } this.expressApp.listen(port, function () { (0, logger_1.logMessage)("Faker Server running on \n \u001B[42m http://localhost:".concat(port).concat(_this.serverPath, "\u001B[0m "), "debug"); }); }; /** * Adds a new request method handle to the faker server * @param path - The url the handler should handle * @param handler - The handler it self * @param method - The request method type the handle should accept */ FakerServer.prototype.__addMethodRequestHandler = function (path, handler, method) { if (!this.methodRequestHanders.has(path)) { this.methodRequestHanders.set(path, {}); } var _handlers = this.methodRequestHanders.get(path); if (_handlers) _handlers[method] = handler; }; /** * Adds a new GET request handler to the faker server instance * @param path - The url the handler should handle * @param handler - The handler it self * */ FakerServer.prototype.get = function (path, handler) { this.__addMethodRequestHandler(path, handler, "GET"); return this; }; /** * Adds a new POST request handler to the faker server instance * @param path - The url the handler should handle * @param handler - The handler it self * */ FakerServer.prototype.post = function (path, handler) { this.__addMethodRequestHandler(path, handler, "POST"); return this; }; /** * Adds a new DELETE request handler to the faker server instance * @param path - The url the handler should handle * @param handler - The handler it self * */ FakerServer.prototype.delete = function (path, handler) { this.__addMethodRequestHandler(path, handler, "DELETE"); return this; }; /** * Adds a new PUT request handler to the faker server instance * @param path - The url the handler should handle * @param handler - The handler it self * */ FakerServer.prototype.put = function (path, handler) { this.__addMethodRequestHandler(path, handler, "PUT"); return this; }; /** * Adds a new PATCH request handler to the faker server instance * @param path - The url the handler should handle * @param handler - The handler it self * */ FakerServer.prototype.patch = function (path, handler) { this.__addMethodRequestHandler(path, handler, "PATCH"); return this; }; /** * Register a new Router to the faker server instance * @param path - The path the router should handle request to (avoid using paths that ends with a /) * @param router - The router instance * * @remark This method can throw error if the `path` ends with / */ FakerServer.prototype.route = function (path, routerOrViewSet) { var _a, _b; if (!(routerOrViewSet instanceof router_1.Router)) { try { if (path.trimStart().startsWith("/") || path.trimEnd().endsWith("/")) { throw new Error("Path starting or ending with / is not allowed when registering a viewset"); } var viewset = routerOrViewSet; this.__internalRouter.register(path, viewset); return; } catch (error) { var e = error; (0, logger_1.logMessage)("".concat(e.message, " \n ").concat((_a = e.stack) === null || _a === void 0 ? void 0 : _a.split("\n").splice(0, 3).join("\n"))); } } var router = routerOrViewSet; try { if (path.match(/\/$/) && path !== this.__internlRouterRoot) { throw new Error("Avoid using router path that ends with \u001B[41m\u001B[37m / \u001B[0m "); } if (this.routerMaps.has(path)) { throw new Error("Another router with thesame path ".concat(path, " is been override @ \n ")); } } catch (error) { var _e = error; var requiredStag = (_b = _e.stack) === null || _b === void 0 ? void 0 : _b.split("\n").slice(1, 3).join("\n"); (0, logger_1.logMessage)("".concat(_e.message, " \n ").concat(requiredStag, " \n"), "warning"); } router._root = path; this.routerMaps.set(path, router); }; /** * Handles request that matches a specific static path that has a method handler registered to it * * @param path - The url the handler should handle * @param handler - The handler it self * @param method - The request method type the handle should accept */ FakerServer.prototype._handleMethodHandler = function (request, response, path, params) { // Gets all method handlers associated to the path var handlers = this.methodRequestHanders.get(path); var method = request.method.toUpperCase(); // The method is an Option request,Add the handlers methods to the response Accept header if (!(method in handlers)) { if (method === "OPTIONS") { response.setHeader("Accept", Object.keys(handlers).join(",")); } return false; } var handler = handlers[method]; // Could not the a handler for the request method type if (!handler) return false; // The handler was is a function if (typeof handler === "function") { handler(request, response, params); return true; } else if (handler instanceof models_1.AbstractModel) { // Handler is a model send the model's generated data response.send(handler.generate(request, params)); return true; } else if (handler instanceof transformers_1.Transformer) { // The handler is a transformer call the transform function and send the data it returns response.send(handler.transform(request, params)); return true; } else { response.send(handler); } return false; }; /** * Called internally to check if there exist a router that can handle a request, after confirming that there is no method handler found to handle the request * @param request - The request object * @param response - The response object * path - The request path without the server prefix path * @returns - true if the request handled by a router or false if there was no router to handle the request */ FakerServer.prototype._handleRouterRequest = function (request, response, path) { // Get all the routers path prefix var routersPath = Array.from(this.routerMaps.keys()); // loop through the routerPath to see those that match the start of the path for (var _i = 0, routersPath_1 = routersPath; _i < routersPath_1.length; _i++) { var routerPath = routersPath_1[_i]; if (path.startsWith(routerPath) && routerPath !== this.__internlRouterRoot) { // A match was found // strip the prefix of the router from the path var _m = path.replace(routerPath, ""); // This insures that the right router is select since router prefix are not allowed to end with / /** * This plevent for example * router prefix is router/game * then path router/game/more * should match the router but * path = router/game//more will not macth */ if (!_m.startsWith("/")) continue; var router = this.routerMaps.get(routerPath); // pass the request to the found router and see if it can handle the request var result = router.on(request, response, _m); if (result) return true; } else if (routerPath === this.__internlRouterRoot) { // For internal router , This is to handle ViewSet that where passed into the route feature, there is no need to strip the router path var router = this.routerMaps.get(routerPath); // pass the request to the found router and see if it can handle the request var result = router.on(request, response, path); if (result) return true; } continue; } return false; }; /** * This method is called internally everytime a new request is directed to the faker server * @param request - The new request object * @param response - The request response object */ FakerServer.prototype.onNewRequest = function (request, response) { var path = request.path.replace(this.serverPath, "").trim(); var tempPattern = RegExp("\/$"); if (!path.match(tempPattern)) { path = path + "/"; } if (request.method === "OPTIONS") response.setHeader("Accept", ""); (0, logger_1.logRequest)(request); var handled = false; // First loop through Method handlers first // loop through each method handler if path matches current request path var handlersPath = Array.from(this.methodRequestHanders.keys()); for (var _i = 0, handlersPath_1 = handlersPath; _i < handlersPath_1.length; _i++) { var handlerPath = handlersPath_1[_i]; if (handled) break; // Run the pathParams finder if the paths maches it will return an object of paramsType var pathMatchResult = path_1.PathUtil.isMatch(handlerPath, path, true); if (pathMatchResult) { handled = this._handleMethodHandler(request, response, handlerPath, pathMatchResult); } } // Pass it to the routers to handle if no method found to handle the request if (handled === false) { handled = this._handleRouterRequest(request, response, path.replace(/^\/\//, "/")); } // no methods or routers available to handle such request if (handled === false) { if (request.method !== "OPTIONS") (0, logger_1.logMessage)("Unhandled request made to `".concat(request.method.toUpperCase(), " ").concat(path, "`"), "error"); try { if (request.method.toUpperCase() === "OPTIONS") { response.status(200); response.send(); } else { response.status(404); response.send({ detail: "No handler for this route @FakerAPI", }); } } catch (error) { // Todo: Handle this error } } }; return FakerServer; }()); exports.FakerServer = FakerServer; //# sourceMappingURL=index.js.map