UNPKG

@athenna/http

Version:

The Athenna Http server. Built on top of fastify.

206 lines (205 loc) 5.93 kB
/** * @athenna/http * * (c) João Lenon <lenon@athenna.io> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ import { Route } from '#src/router/Route'; import { Server } from '#src/facades/Server'; import { Is, Macroable } from '@athenna/common'; import { RouteGroup } from '#src/router/RouteGroup'; import { RouteResource } from '#src/router/RouteResource'; import { UndefinedMethodException } from '#src/exceptions/UndefinedMethodException'; export class Router extends Macroable { constructor() { super(...arguments); /** * All routes registered. */ this.routes = []; /** * Route groups opened. */ this.openedGroups = []; } /** * List the routes registered. */ list() { return this.toJSON(this.routes); } /** * Set the controller instance. */ controller(controller) { if (Is.String(controller)) { controller = ioc.safeUse(`App/Http/Controllers/${controller}`); } this.controllerInstance = controller; return this; } /** * Add route for a given pattern and methods */ route(pattern, methods, handler) { if (this.isValidControllerHandler(handler)) { if (!this.controllerInstance[handler]) { throw new UndefinedMethodException(handler, this.controllerInstance.name); } handler = this.controllerInstance[handler]; } const route = new Route(pattern, methods, handler); const openedGroup = this.getRecentGroup(); if (openedGroup) { openedGroup.routes.push(route); } else { this.routes.push(route); } return route; } /** * Creates a vanilla fastify route without using Athenna router. */ vanillaRoute(options) { return Server.fastify.route(options); } /** * Creates a new route resource. */ resource(resource, controller) { const resourceInstance = new RouteResource(resource, controller || this.controllerInstance); const openedGroup = this.getRecentGroup(); if (openedGroup) { openedGroup.routes.push(resourceInstance); } else { this.routes.push(resourceInstance); } return resourceInstance; } /** * This method is a convenient shortcut to render a view without * defining an explicit handler. */ view(pattern, view, data) { return this.route(pattern, ['GET', 'HEAD'], ctx => { return ctx.response.view(view, data); }); } /** * This method is a convenient shortcut to redirect a route without * defining an explicit handler. */ redirect(pattern, url, status) { return this.route(pattern, ['GET', 'HEAD'], ctx => { return ctx.response.redirectTo(url, status); }); } /** * Define a route that handles all common HTTP methods. */ any(pattern, handler) { return this.route(pattern, ['HEAD', 'OPTIONS', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'], handler); } /** * Define GET route. */ get(pattern, handler) { return this.route(pattern, ['GET', 'HEAD'], handler); } /** * Define HEAD route. */ head(pattern, handler) { return this.route(pattern, ['HEAD'], handler); } /** * Define POST route. */ post(pattern, handler) { return this.route(pattern, ['POST'], handler); } /** * Define PUT route. */ put(pattern, handler) { return this.route(pattern, ['PUT'], handler); } /** * Define PATCH route. */ patch(pattern, handler) { return this.route(pattern, ['PATCH'], handler); } /** * Define DELETE route. */ delete(pattern, handler) { return this.route(pattern, ['DELETE'], handler); } /** * Define OPTIONS route. */ options(pattern, handler) { return this.route(pattern, ['OPTIONS'], handler); } /** * Creates a group of routes. Anything applied in route groups will be applied * in the routes that are inside that group. */ group(callback) { const group = new RouteGroup([]); const openedGroup = this.getRecentGroup(); if (openedGroup) { openedGroup.routes.push(group); } else { this.routes.push(group); } this.openedGroups.push(group); callback(); this.openedGroups.pop(); return group; } /** * Register all the routes inside the http server. After routes are registered, * anyone could be registered anymore. */ register() { this.toJSON(this.routes).forEach(route => Server.route(route)); } /** * Transform some route array to a route json array. */ toJSON(routes) { return routes.reduce((list, route) => { if (route instanceof RouteGroup) { list = list.concat(this.toJSON(route.routes)); return list; } if (route instanceof RouteResource) { list = list.concat(this.toJSON(route.routes)); return list; } if (!route.route.deleted) { list.push(route.toJSON()); } return list; }, []); } /** * Get the most recent route group created. */ getRecentGroup() { return this.openedGroups[this.openedGroups.length - 1]; } /** * Indicates if if a valid controller handler method. */ isValidControllerHandler(handler) { return (this.controllerInstance && Is.String(handler) && !handler.includes('.')); } }