Request handlers & error response factory!
This commit is contained in:
@@ -9,12 +9,31 @@ export interface CanonicalDefinition {
|
||||
imported: any,
|
||||
}
|
||||
|
||||
export interface CanonicalReference {
|
||||
resource?: string,
|
||||
item: string,
|
||||
particular?: string,
|
||||
}
|
||||
|
||||
export class Canonical<T> extends LifecycleUnit {
|
||||
protected base_path: string = '.'
|
||||
protected suffix: string = '.ts'
|
||||
protected canonical_item: string = ''
|
||||
protected _items: { [key: string]: T } = {}
|
||||
|
||||
public static resolve(reference: string): CanonicalReference {
|
||||
const rsc_parts = reference.split('::')
|
||||
const resource = rsc_parts.length > 1 ? rsc_parts[0] + 's' : undefined
|
||||
const rsc_less = rsc_parts.length > 1 ? rsc_parts[1] : rsc_parts[0]
|
||||
const prt_parts = rsc_less.split('.')
|
||||
const item = prt_parts[0]
|
||||
const particular = prt_parts.length > 1 ? prt_parts.slice(1).join('.') : undefined
|
||||
|
||||
return {
|
||||
resource, item, particular
|
||||
}
|
||||
}
|
||||
|
||||
public all(): string[] {
|
||||
return Object.keys(this._items)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import SessionInterface from '../http/session/SessionInterface.ts'
|
||||
import InjectSession from '../http/kernel/module/InjectSession.ts'
|
||||
import PersistSession from '../http/kernel/module/PersistSession.ts'
|
||||
import MountActivatedRoute from '../http/kernel/module/MountActivatedRoute.ts'
|
||||
import ApplyRouteHandlers from '../http/kernel/module/ApplyRouteHandlers.ts'
|
||||
|
||||
@Unit()
|
||||
export default class HttpKernel extends LifecycleUnit {
|
||||
@@ -69,6 +70,8 @@ export default class HttpKernel extends LifecycleUnit {
|
||||
PersistSession.register(this.kernel)
|
||||
MountActivatedRoute.register(this.kernel)
|
||||
|
||||
ApplyRouteHandlers.register(this.kernel)
|
||||
|
||||
if ( this.config.get('server.powered_by.enable') ) {
|
||||
SetDatonHeaders.register(this.kernel)
|
||||
}
|
||||
|
||||
@@ -4,21 +4,35 @@ import Routes from './Routes.ts'
|
||||
import {RouterDefinition} from '../http/type/RouterDefinition.ts'
|
||||
import {Collection} from '../collection/Collection.ts'
|
||||
import {Route} from '../http/routing/Route.ts'
|
||||
import {SimpleRoute} from "../http/routing/SimpleRoute.ts";
|
||||
import {ComplexRoute} from "../http/routing/ComplexRoute.ts";
|
||||
import ActivatedRoute from "../http/routing/ActivatedRoute.ts";
|
||||
import {SimpleRoute} from '../http/routing/SimpleRoute.ts'
|
||||
import {ComplexRoute} from '../http/routing/ComplexRoute.ts'
|
||||
import ActivatedRoute from '../http/routing/ActivatedRoute.ts'
|
||||
import {Request} from '../http/Request.ts'
|
||||
import ResponseFactory from '../http/response/ResponseFactory.ts'
|
||||
import {Canonical} from './Canonical.ts'
|
||||
import {Logging} from '../service/logging/Logging.ts'
|
||||
import {Canon} from './Canon.ts'
|
||||
import {isBindable} from '../lifecycle/AppClass.ts'
|
||||
|
||||
export type RouteHandler = () => any
|
||||
export type RouteHandler = (request: Request) => Request | Promise<Request> | ResponseFactory | Promise<ResponseFactory> | void | Promise<void>
|
||||
export type RouteHandlers = RouteHandler[]
|
||||
export interface RouteDefinition {
|
||||
get?: RouteHandler,
|
||||
post?: RouteHandler,
|
||||
patch?: RouteHandler,
|
||||
delete?: RouteHandler,
|
||||
head?: RouteHandler,
|
||||
put?: RouteHandler,
|
||||
connect?: RouteHandler,
|
||||
options?: RouteHandler,
|
||||
trace?: RouteHandler,
|
||||
get?: RouteHandlers,
|
||||
post?: RouteHandlers,
|
||||
patch?: RouteHandlers,
|
||||
delete?: RouteHandlers,
|
||||
head?: RouteHandlers,
|
||||
put?: RouteHandlers,
|
||||
connect?: RouteHandlers,
|
||||
options?: RouteHandlers,
|
||||
trace?: RouteHandlers,
|
||||
}
|
||||
|
||||
export function isRouteHandler(what: any): what is RouteHandler {
|
||||
return (
|
||||
typeof what === 'function'
|
||||
|| typeof what.handleRequest === 'function'
|
||||
)
|
||||
}
|
||||
|
||||
const verbs = ['get', 'post', 'patch', 'delete', 'head', 'put', 'connect', 'options', 'trace']
|
||||
@@ -30,6 +44,8 @@ export default class Routing extends LifecycleUnit {
|
||||
|
||||
constructor(
|
||||
protected readonly routes: Routes,
|
||||
protected readonly logger: Logging,
|
||||
protected readonly canon: Canon,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
@@ -56,7 +72,7 @@ export default class Routing extends LifecycleUnit {
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
this.definitions[base][verb] = this.build_handler(handlers) // TODO want to rework this
|
||||
this.definitions[base][verb] = this.build_handler(handlers)
|
||||
this.instances.push(this.build_route(base))
|
||||
}
|
||||
}
|
||||
@@ -64,9 +80,46 @@ export default class Routing extends LifecycleUnit {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
public build_handler(group: string[]): () => any {
|
||||
return () => {}
|
||||
public build_handler(group: string[]): RouteHandlers {
|
||||
const handlers: RouteHandlers = []
|
||||
for ( const item of group ) {
|
||||
const ref = Canonical.resolve(item)
|
||||
|
||||
if ( !ref.resource ) {
|
||||
this.logger.error(`Invalid canonical reference for route: ${item}. Reference must include resource (e.g. controller::)!`)
|
||||
continue
|
||||
}
|
||||
|
||||
const resource = this.canon.resource(ref.resource)
|
||||
const resolved = resource.get(ref.item)
|
||||
|
||||
if ( !ref.particular ) {
|
||||
if ( isRouteHandler(resolved) ) {
|
||||
handlers.push(resolved)
|
||||
} else {
|
||||
throw new TypeError(`Invalid canonical reference for route: ${item}. Reference is not a valid route handler.`)
|
||||
}
|
||||
} else {
|
||||
if ( isBindable(resolved) ) {
|
||||
let handler
|
||||
try {
|
||||
handler = resolved.get_bound_method(ref.particular)
|
||||
} catch (e) {
|
||||
this.logger.error(e)
|
||||
throw new Error(`Invalid canonical reference for route: ${item}. Reference particular could not be bound.`)
|
||||
}
|
||||
|
||||
if ( isRouteHandler(handler) ) {
|
||||
handlers.push(handler)
|
||||
} else {
|
||||
throw new TypeError(`Invalid canonical reference for route: ${item}. Reference is not a valid route handler.`)
|
||||
}
|
||||
} else {
|
||||
throw new TypeError(`Invalid canonical reference for route: ${item}. Reference specifies particular, but resolved resource is not bindable.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
return handlers
|
||||
}
|
||||
|
||||
public resolve(parts: string[]): string {
|
||||
@@ -96,10 +149,13 @@ export default class Routing extends LifecycleUnit {
|
||||
return this.instances.firstWhere((route: Route) => route.match(incoming))
|
||||
}
|
||||
|
||||
public build(incoming: string): ActivatedRoute | undefined {
|
||||
public build(incoming: string, method: string): ActivatedRoute | undefined {
|
||||
const route: Route | undefined = this.match(incoming)
|
||||
|
||||
if ( route ) {
|
||||
return new ActivatedRoute(incoming, route)
|
||||
// @ts-ignore
|
||||
const handlers: RouteHandlers | undefined = this.definitions[route.route][method]
|
||||
return new ActivatedRoute(incoming, route, handlers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user