@athenna/http
Version:
The Athenna Http server. Built on top of fastify.
206 lines (205 loc) • 5.93 kB
JavaScript
/**
* @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('.'));
}
}