Add mounting for activated routes, route compiling, routing
This commit is contained in:
parent
338b9be506
commit
3acc1bc83e
33
src/http/kernel/module/MountActivatedRouteHTTPModule.ts
Normal file
33
src/http/kernel/module/MountActivatedRouteHTTPModule.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import {Injectable, Inject} from "@extollo/di"
|
||||||
|
import {HTTPKernelModule} from "../HTTPKernelModule";
|
||||||
|
import {HTTPKernel} from "../HTTPKernel";
|
||||||
|
import {Request} from "../../lifecycle/Request";
|
||||||
|
import {Routing} from "../../../service/Routing";
|
||||||
|
import {ActivatedRoute} from "../../routing/ActivatedRoute";
|
||||||
|
import {Logging} from "../../../service/Logging";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MountActivatedRouteHTTPModule extends HTTPKernelModule {
|
||||||
|
@Inject()
|
||||||
|
protected readonly routing!: Routing
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
protected readonly logging!: Logging
|
||||||
|
|
||||||
|
public static register(kernel: HTTPKernel) {
|
||||||
|
kernel.register(this).before()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async apply(request: Request): Promise<Request> {
|
||||||
|
const route = this.routing.match(request.method, request.path)
|
||||||
|
if ( route ) {
|
||||||
|
this.logging.verbose(`Mounting activated route: ${request.path} -> ${route}`)
|
||||||
|
const activated = new ActivatedRoute(route, request.path)
|
||||||
|
request.registerSingletonInstance<ActivatedRoute>(ActivatedRoute, activated)
|
||||||
|
} else {
|
||||||
|
this.logging.debug(`No matching route found for: ${request.method} -> ${request.path}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ import {Request} from "../../lifecycle/Request";
|
|||||||
import {Session} from "../../session/Session";
|
import {Session} from "../../session/Session";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PersistSessionHTTPMiddleware extends HTTPKernelModule {
|
export class PersistSessionHTTPModule extends HTTPKernelModule {
|
||||||
public static register(kernel: HTTPKernel) {
|
public static register(kernel: HTTPKernel) {
|
||||||
kernel.register(this).last()
|
kernel.register(this).last()
|
||||||
}
|
}
|
@ -1,17 +1,23 @@
|
|||||||
import {HTTPKernelModule} from "../HTTPKernelModule";
|
import {HTTPKernelModule} from "../HTTPKernelModule";
|
||||||
import {Request} from "../../lifecycle/Request";
|
import {Request} from "../../lifecycle/Request";
|
||||||
import {Injectable} from "@extollo/di"
|
import {Injectable, Inject} from "@extollo/di"
|
||||||
import {HTTPKernel} from "../HTTPKernel";
|
import {HTTPKernel} from "../HTTPKernel";
|
||||||
|
import {Config} from "../../../service/Config";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PoweredByHeaderInjectionHTTPModule extends HTTPKernelModule {
|
export class PoweredByHeaderInjectionHTTPModule extends HTTPKernelModule {
|
||||||
|
@Inject()
|
||||||
|
protected readonly config!: Config;
|
||||||
|
|
||||||
public static register(kernel: HTTPKernel) {
|
public static register(kernel: HTTPKernel) {
|
||||||
kernel.register(this).after()
|
kernel.register(this).after()
|
||||||
}
|
}
|
||||||
|
|
||||||
public async apply(request: Request) {
|
public async apply(request: Request) {
|
||||||
// FIXME make this configurable
|
if ( !this.config.get('server.poweredBy.hide', false) ) {
|
||||||
request.response.setHeader('X-Powered-By', 'Extollo')
|
request.response.setHeader('X-Powered-By', this.config.get('server.poweredBy.header', 'Extollo'))
|
||||||
|
}
|
||||||
|
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ export class SetSessionCookieHTTPModule extends HTTPKernelModule {
|
|||||||
const session = `${uuid_v4()}-${uuid_v4()}`
|
const session = `${uuid_v4()}-${uuid_v4()}`
|
||||||
|
|
||||||
this.logging.verbose(`Starting session: ${session}`)
|
this.logging.verbose(`Starting session: ${session}`)
|
||||||
request.cookies.set('extollo.session', session) // FIXME allow configuring this
|
request.cookies.set('extollo.session', session)
|
||||||
}
|
}
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import {HTTPCookieJar} from "../kernel/HTTPCookieJar";
|
|||||||
import {TLSSocket} from "tls";
|
import {TLSSocket} from "tls";
|
||||||
import * as url from "url";
|
import * as url from "url";
|
||||||
import {Response} from "./Response";
|
import {Response} from "./Response";
|
||||||
|
import {ActivatedRoute} from "../routing/ActivatedRoute";
|
||||||
|
|
||||||
// FIXME - add others?
|
// FIXME - add others?
|
||||||
export type HTTPMethod = 'post' | 'get' | 'patch' | 'put' | 'delete' | 'unknown';
|
export type HTTPMethod = 'post' | 'get' | 'patch' | 'put' | 'delete' | 'unknown';
|
||||||
|
23
src/http/routing/ActivatedRoute.ts
Normal file
23
src/http/routing/ActivatedRoute.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import {ErrorWithContext} from "@extollo/util";
|
||||||
|
import {Route} from "./Route";
|
||||||
|
|
||||||
|
export class ActivatedRoute {
|
||||||
|
public readonly params: {[key: string]: string}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly route: Route,
|
||||||
|
public readonly path: string
|
||||||
|
) {
|
||||||
|
const params = route.extract(path)
|
||||||
|
if ( !params ) {
|
||||||
|
const error = new ErrorWithContext('Cannot get params for route. Path does not match.')
|
||||||
|
error.context = {
|
||||||
|
matchedRoute: String(route),
|
||||||
|
requestPath: path,
|
||||||
|
}
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
this.params = params
|
||||||
|
}
|
||||||
|
}
|
141
src/http/routing/Route.ts
Normal file
141
src/http/routing/Route.ts
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
import {AppClass} from "../../lifecycle/AppClass";
|
||||||
|
import {HTTPMethod, Request} from "../lifecycle/Request";
|
||||||
|
import {Application} from "../../lifecycle/Application";
|
||||||
|
import {RouteGroup} from "./RouteGroup";
|
||||||
|
|
||||||
|
export type RouteHandler = (request: Request) => void | Promise<void> // FIXME want to do some improvements here
|
||||||
|
|
||||||
|
// TODO middleware, domains, named routes - support this on groups as well
|
||||||
|
|
||||||
|
export class Route extends AppClass {
|
||||||
|
private static registeredRoutes: Route[] = []
|
||||||
|
private static registeredGroups: RouteGroup[] = []
|
||||||
|
|
||||||
|
private static compiledGroupStack: RouteGroup[] = []
|
||||||
|
|
||||||
|
public static registerGroup(group: RouteGroup) {
|
||||||
|
this.registeredGroups.push(group)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async compile(): Promise<Route[]> {
|
||||||
|
let registeredRoutes = this.registeredRoutes
|
||||||
|
const registeredGroups = this.registeredGroups
|
||||||
|
|
||||||
|
this.registeredRoutes = []
|
||||||
|
this.registeredGroups = []
|
||||||
|
|
||||||
|
const stack = [...this.compiledGroupStack].reverse()
|
||||||
|
for ( const route of registeredRoutes ) {
|
||||||
|
for ( const group of stack ) {
|
||||||
|
route.prepend(group.prefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( const group of registeredGroups ) {
|
||||||
|
this.compiledGroupStack.push(group)
|
||||||
|
await group.group()
|
||||||
|
|
||||||
|
const childCompilation = await this.compile()
|
||||||
|
registeredRoutes = registeredRoutes.concat(childCompilation)
|
||||||
|
|
||||||
|
this.compiledGroupStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
return registeredRoutes
|
||||||
|
}
|
||||||
|
|
||||||
|
public static endpoint(method: HTTPMethod | HTTPMethod[], definition: string, handler: RouteHandler) {
|
||||||
|
const route = new Route(method, handler, definition)
|
||||||
|
this.registeredRoutes.push(route)
|
||||||
|
return route
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get(definition: string, handler: RouteHandler) {
|
||||||
|
return this.endpoint('get', definition, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static post(definition: string, handler: RouteHandler) {
|
||||||
|
return this.endpoint('post', definition, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static put(definition: string, handler: RouteHandler) {
|
||||||
|
return this.endpoint('put', definition, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static patch(definition: string, handler: RouteHandler) {
|
||||||
|
return this.endpoint('patch', definition, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static delete(definition: string, handler: RouteHandler) {
|
||||||
|
return this.endpoint('delete', definition, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static any(definition: string, handler: RouteHandler) {
|
||||||
|
return this.endpoint(['get', 'put', 'patch', 'post', 'delete'], definition, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static group(prefix: string, group: () => void | Promise<void>) {
|
||||||
|
const grp = <RouteGroup> Application.getApplication().make(RouteGroup, group, prefix)
|
||||||
|
this.registeredGroups.push(grp)
|
||||||
|
return grp
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected method: HTTPMethod | HTTPMethod[],
|
||||||
|
protected handler: RouteHandler,
|
||||||
|
protected route: string
|
||||||
|
) { super() }
|
||||||
|
|
||||||
|
public match(method: HTTPMethod, potential: string): boolean {
|
||||||
|
if ( Array.isArray(this.method) && !this.method.includes(method) ) return false
|
||||||
|
else if ( !Array.isArray(this.method) && this.method !== method ) return false
|
||||||
|
|
||||||
|
return !!this.extract(potential)
|
||||||
|
}
|
||||||
|
|
||||||
|
public extract(potential: string): {[key: string]: string} | undefined {
|
||||||
|
const routeParts = (this.route.startsWith('/') ? this.route.substr(1) : this.route).split('/')
|
||||||
|
const potentialParts = (potential.startsWith('/') ? potential.substr(1) : potential).split('/')
|
||||||
|
|
||||||
|
const params: any = {}
|
||||||
|
let wildcardIdx = 0
|
||||||
|
|
||||||
|
for ( let i = 0; i < routeParts.length; i += 1 ) {
|
||||||
|
const part = routeParts[i]
|
||||||
|
|
||||||
|
if ( part === '**' ) {
|
||||||
|
params[wildcardIdx] = potentialParts.slice(i).join('/')
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (potentialParts.length - 1) < i ) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( part === '*' ) {
|
||||||
|
params[wildcardIdx] = potentialParts[i]
|
||||||
|
wildcardIdx += 1
|
||||||
|
} else if ( part.startsWith(':') ) {
|
||||||
|
params[part.substr(1)] = potentialParts[i]
|
||||||
|
} else if ( potentialParts[i] !== part ) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we got here, we didn't find a **
|
||||||
|
// So, if the lengths are different, fail
|
||||||
|
if ( routeParts.length !== potentialParts.length ) return
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
private prepend(prefix: string) {
|
||||||
|
if ( !prefix.endsWith('/') ) prefix = `${prefix}/`
|
||||||
|
if ( this.route.startsWith('/') ) this.route = this.route.substring(1)
|
||||||
|
this.route = `${prefix}${this.route}`
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
const method = Array.isArray(this.method) ? this.method : [this.method]
|
||||||
|
return `${method.join('|')} -> ${this.route}`
|
||||||
|
}
|
||||||
|
}
|
14
src/http/routing/RouteGroup.ts
Normal file
14
src/http/routing/RouteGroup.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import {AppClass} from "../../lifecycle/AppClass";
|
||||||
|
|
||||||
|
export class RouteGroup extends AppClass {
|
||||||
|
private static currentGroupNesting: RouteGroup[] = []
|
||||||
|
|
||||||
|
public static getCurrentGroupHierarchy(): RouteGroup[] {
|
||||||
|
return [...this.currentGroupNesting]
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly group: () => void | Promise<void>,
|
||||||
|
public readonly prefix: string
|
||||||
|
) { super() }
|
||||||
|
}
|
@ -3,25 +3,29 @@ import {
|
|||||||
Container,
|
Container,
|
||||||
DependencyRequirement,
|
DependencyRequirement,
|
||||||
PropertyDependency,
|
PropertyDependency,
|
||||||
|
isInstantiable,
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
DEPENDENCY_KEYS_METADATA_KEY,
|
||||||
DEPENDENCY_KEYS_PROPERTY_METADATA_KEY
|
DEPENDENCY_KEYS_PROPERTY_METADATA_KEY
|
||||||
} from "@extollo/di"
|
} from "@extollo/di"
|
||||||
import {Collection} from "@extollo/util"
|
import {Collection, ErrorWithContext} from "@extollo/util"
|
||||||
import {MemorySession} from "./MemorySession";
|
import {MemorySession} from "./MemorySession";
|
||||||
import {Session} from "./Session";
|
import {Session} from "./Session";
|
||||||
import {Logging} from "../../service/Logging";
|
import {Logging} from "../../service/Logging";
|
||||||
|
import {Config} from "../../service/Config";
|
||||||
|
|
||||||
export class SessionFactory extends AbstractFactory {
|
export class SessionFactory extends AbstractFactory {
|
||||||
protected readonly logging: Logging
|
protected readonly logging: Logging
|
||||||
|
protected readonly config: Config
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({})
|
super({})
|
||||||
this.logging = Container.getContainer().make<Logging>(Logging)
|
this.logging = Container.getContainer().make<Logging>(Logging)
|
||||||
|
this.config = Container.getContainer().make<Config>(Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(dependencies: any[], parameters: any[]): any {
|
produce(dependencies: any[], parameters: any[]): Session {
|
||||||
this.logging.warn(`You are using the default memory-based session driver. It is recommended you configure a persistent session driver instead.`)
|
this.logging.warn(`You are using the default memory-based session driver. It is recommended you configure a persistent session driver instead.`)
|
||||||
return new MemorySession() // FIXME allow configuring
|
return new (this.getSessionClass())
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: any) {
|
match(something: any) {
|
||||||
@ -29,14 +33,14 @@ export class SessionFactory extends AbstractFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
getDependencyKeys(): Collection<DependencyRequirement> {
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.token)
|
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getSessionClass())
|
||||||
if ( meta ) return meta
|
if ( meta ) return meta
|
||||||
return new Collection<DependencyRequirement>()
|
return new Collection<DependencyRequirement>()
|
||||||
}
|
}
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
getInjectedProperties(): Collection<PropertyDependency> {
|
||||||
const meta = new Collection<PropertyDependency>()
|
const meta = new Collection<PropertyDependency>()
|
||||||
let currentToken = MemorySession // FIXME allow configuring
|
let currentToken = this.getSessionClass()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
const loadedMeta = Reflect.getMetadata(DEPENDENCY_KEYS_PROPERTY_METADATA_KEY, currentToken)
|
const loadedMeta = Reflect.getMetadata(DEPENDENCY_KEYS_PROPERTY_METADATA_KEY, currentToken)
|
||||||
@ -46,4 +50,19 @@ export class SessionFactory extends AbstractFactory {
|
|||||||
|
|
||||||
return meta
|
return meta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getSessionClass() {
|
||||||
|
const SessionClass = this.config.get('server.session.driver', MemorySession)
|
||||||
|
|
||||||
|
// TODO check that session class is valid
|
||||||
|
if ( !isInstantiable(SessionClass) || !(SessionClass.prototype instanceof Session) ) {
|
||||||
|
const e = new ErrorWithContext('Provided session class does not extend from @extollo/lib.Session');
|
||||||
|
e.context = {
|
||||||
|
config_key: 'server.session.driver',
|
||||||
|
class: SessionClass.toString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SessionClass
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
17
src/index.ts
17
src/index.ts
@ -5,8 +5,24 @@ export * from './lifecycle/Application'
|
|||||||
export * from './lifecycle/AppClass'
|
export * from './lifecycle/AppClass'
|
||||||
export * from './lifecycle/Unit'
|
export * from './lifecycle/Unit'
|
||||||
|
|
||||||
|
export * from './http/kernel/module/InjectSessionHTTPModule'
|
||||||
|
export * from './http/kernel/module/PersistSessionHTTPModule'
|
||||||
|
export * from './http/kernel/module/PoweredByHeaderInjectionHTTPModule'
|
||||||
|
export * from './http/kernel/module/SetSessionCookieHTTPModule'
|
||||||
|
|
||||||
export * from './http/kernel/HTTPKernel'
|
export * from './http/kernel/HTTPKernel'
|
||||||
export * from './http/kernel/HTTPKernelModule'
|
export * from './http/kernel/HTTPKernelModule'
|
||||||
|
export * from './http/kernel/HTTPCookieJar'
|
||||||
|
|
||||||
|
export * from './http/lifecycle/Request'
|
||||||
|
export * from './http/lifecycle/Response'
|
||||||
|
|
||||||
|
export * from './http/routing/Route'
|
||||||
|
export * from './http/routing/RouteGroup'
|
||||||
|
|
||||||
|
export * from './http/session/Session'
|
||||||
|
export * from './http/session/SessionFactory'
|
||||||
|
export * from './http/session/MemorySession'
|
||||||
|
|
||||||
export * from './http/Controller'
|
export * from './http/Controller'
|
||||||
|
|
||||||
@ -18,3 +34,4 @@ export * from './service/FakeCanonical'
|
|||||||
export * from './service/Config'
|
export * from './service/Config'
|
||||||
export * from './service/Controllers'
|
export * from './service/Controllers'
|
||||||
export * from './service/HTTPServer'
|
export * from './service/HTTPServer'
|
||||||
|
export * from './service/Routing'
|
||||||
|
@ -7,7 +7,8 @@ import {HTTPKernel} from "../http/kernel/HTTPKernel";
|
|||||||
import {PoweredByHeaderInjectionHTTPModule} from "../http/kernel/module/PoweredByHeaderInjectionHTTPModule";
|
import {PoweredByHeaderInjectionHTTPModule} from "../http/kernel/module/PoweredByHeaderInjectionHTTPModule";
|
||||||
import {SetSessionCookieHTTPModule} from "../http/kernel/module/SetSessionCookieHTTPModule";
|
import {SetSessionCookieHTTPModule} from "../http/kernel/module/SetSessionCookieHTTPModule";
|
||||||
import {InjectSessionHTTPModule} from "../http/kernel/module/InjectSessionHTTPModule";
|
import {InjectSessionHTTPModule} from "../http/kernel/module/InjectSessionHTTPModule";
|
||||||
import {PersistSessionHTTPMiddleware} from "../http/kernel/module/PersistSessionHTTPMiddleware";
|
import {PersistSessionHTTPModule} from "../http/kernel/module/PersistSessionHTTPModule";
|
||||||
|
import {MountActivatedRouteHTTPModule} from "../http/kernel/module/MountActivatedRouteHTTPModule";
|
||||||
|
|
||||||
@Singleton()
|
@Singleton()
|
||||||
export class HTTPServer extends Unit {
|
export class HTTPServer extends Unit {
|
||||||
@ -26,7 +27,8 @@ export class HTTPServer extends Unit {
|
|||||||
PoweredByHeaderInjectionHTTPModule.register(this.kernel)
|
PoweredByHeaderInjectionHTTPModule.register(this.kernel)
|
||||||
SetSessionCookieHTTPModule.register(this.kernel)
|
SetSessionCookieHTTPModule.register(this.kernel)
|
||||||
InjectSessionHTTPModule.register(this.kernel)
|
InjectSessionHTTPModule.register(this.kernel)
|
||||||
PersistSessionHTTPMiddleware.register(this.kernel)
|
PersistSessionHTTPModule.register(this.kernel)
|
||||||
|
MountActivatedRouteHTTPModule.register(this.kernel)
|
||||||
|
|
||||||
await new Promise<void>((res, rej) => {
|
await new Promise<void>((res, rej) => {
|
||||||
this.server = createServer(this.handler)
|
this.server = createServer(this.handler)
|
||||||
|
@ -77,5 +77,7 @@ export class Logging {
|
|||||||
return e.stack.split(/\s+at\s+/)
|
return e.stack.split(/\s+at\s+/)
|
||||||
.slice(level)
|
.slice(level)
|
||||||
.map((x: string): string => x.trim().split(' (')[0].split('.')[0].split(':')[0])[0]
|
.map((x: string): string => x.trim().split(' (')[0].split('.')[0].split(':')[0])[0]
|
||||||
|
.split('/')
|
||||||
|
.reverse()[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
src/service/Routing.ts
Normal file
44
src/service/Routing.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import {Singleton, Inject} from "@extollo/di"
|
||||||
|
import {UniversalPath, Collection} from "@extollo/util"
|
||||||
|
import {Unit} from "../lifecycle/Unit"
|
||||||
|
import {Logging} from "./Logging"
|
||||||
|
import {Route} from "../http/routing/Route";
|
||||||
|
import {HTTPMethod} from "../http/lifecycle/Request";
|
||||||
|
|
||||||
|
@Singleton()
|
||||||
|
export class Routing extends Unit {
|
||||||
|
@Inject()
|
||||||
|
protected readonly logging!: Logging
|
||||||
|
|
||||||
|
protected compiledRoutes: Collection<Route> = new Collection<Route>()
|
||||||
|
|
||||||
|
public async up() {
|
||||||
|
for await ( const entry of this.path.walk() ) {
|
||||||
|
if ( !entry.endsWith('.routes.js') ) {
|
||||||
|
this.logging.debug(`Skipping routes file with invalid suffix: ${entry}`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logging.info(`Importing routes from: ${entry}`)
|
||||||
|
await import(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logging.info('Compiling routes...')
|
||||||
|
this.compiledRoutes = new Collection<Route>(await Route.compile())
|
||||||
|
|
||||||
|
this.logging.info(`Compiled ${this.compiledRoutes.length} route(s).`)
|
||||||
|
this.compiledRoutes.each(route => {
|
||||||
|
this.logging.verbose(`${route}`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public match(method: HTTPMethod, path: string): Route | undefined {
|
||||||
|
return this.compiledRoutes.firstWhere(route => {
|
||||||
|
return route.match(method, path)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public get path(): UniversalPath {
|
||||||
|
return this.app().appPath('http', 'routes')
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user