Request handlers & error response factory!
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import {Request} from '../Request.ts'
|
||||
import Kernel from './Kernel.ts'
|
||||
import AppClass from '../../lifecycle/AppClass.ts'
|
||||
|
||||
export default class Module {
|
||||
export default class Module extends AppClass {
|
||||
public async match(request: Request): Promise<boolean> {
|
||||
return true
|
||||
}
|
||||
|
||||
53
lib/src/http/kernel/module/ApplyRouteHandlers.ts
Normal file
53
lib/src/http/kernel/module/ApplyRouteHandlers.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import Module from '../Module.ts'
|
||||
import {Injectable} from '../../../../../di/src/decorator/Injection.ts'
|
||||
import Kernel from '../Kernel.ts'
|
||||
import {Logging} from '../../../service/logging/Logging.ts'
|
||||
import {Request} from '../../Request.ts'
|
||||
import ResponseFactory from '../../response/ResponseFactory.ts'
|
||||
import ErrorResponseFactory from "../../response/ErrorResponseFactory.ts";
|
||||
|
||||
@Injectable()
|
||||
export default class ApplyRouteHandlers extends Module {
|
||||
public static register(kernel: Kernel) {
|
||||
kernel.register(this).core()
|
||||
}
|
||||
|
||||
constructor(
|
||||
protected readonly logger: Logging,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
public async apply(request: Request): Promise<Request> {
|
||||
if (
|
||||
!request.route
|
||||
|| !request.route.handlers
|
||||
|| request.route.handlers.length < 1
|
||||
) {
|
||||
return request
|
||||
}
|
||||
|
||||
let current_request: Request = request
|
||||
for ( const handler of request.route.handlers ) {
|
||||
try {
|
||||
const result = await handler(current_request)
|
||||
if ( result instanceof Request ) {
|
||||
// If we got a request instance back, use that for further handlers
|
||||
current_request = result
|
||||
} else if ( result instanceof ResponseFactory ) {
|
||||
// If we got a response factory back, write the response and move along
|
||||
return await result.write(current_request)
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.error('Error encountered while applying request handlers!')
|
||||
this.logger.error(e)
|
||||
|
||||
// TODO determine response type (html | json, &c.)
|
||||
const error_response: ErrorResponseFactory = this.make(ErrorResponseFactory, e)
|
||||
return await error_response.write(request)
|
||||
}
|
||||
}
|
||||
|
||||
return current_request
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export default class MountActivatedRoute extends Module {
|
||||
}
|
||||
}
|
||||
|
||||
const activated_route: ActivatedRoute | undefined = this.routing.build(incoming)
|
||||
const activated_route: ActivatedRoute | undefined = this.routing.build(incoming, request.method.toLowerCase())
|
||||
if ( activated_route ) {
|
||||
this.logger.verbose(`Resolved activated route: ${activated_route.route.route}`)
|
||||
request.route = activated_route
|
||||
|
||||
50
lib/src/http/response/ErrorResponseFactory.ts
Normal file
50
lib/src/http/response/ErrorResponseFactory.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import ResponseFactory from "./ResponseFactory.ts";
|
||||
import {Request} from "../Request.ts";
|
||||
|
||||
export default class ErrorResponseFactory extends ResponseFactory {
|
||||
constructor(
|
||||
public readonly error: Error,
|
||||
public readonly output: 'json' | 'html' = 'html',
|
||||
public readonly status: number = 500,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
public async write(request: Request): Promise<Request> {
|
||||
request.response.status = this.status
|
||||
|
||||
if ( this.output === 'json' ) {
|
||||
request.response.headers.set('Content-Type', 'application/json')
|
||||
request.response.body = this.build_json(this.error)
|
||||
} else if ( this.output === 'html' ) {
|
||||
request.response.headers.set('Content-Type', 'text/html')
|
||||
request.response.body = this.build_html(this.error)
|
||||
}
|
||||
|
||||
return request
|
||||
}
|
||||
|
||||
protected build_html(error: Error) {
|
||||
return `
|
||||
<b>Sorry, an unexpected error occurred while processing your request.</b>
|
||||
<br>
|
||||
<pre><code>
|
||||
Name: ${error.name}
|
||||
Message: ${error.message}
|
||||
Stack trace:
|
||||
- ${error.stack ? error.stack.split(/\s+at\s+/).slice(1).join('<br> - ') : 'none'}
|
||||
</code></pre>
|
||||
`
|
||||
}
|
||||
|
||||
protected build_json(error: Error) {
|
||||
return JSON.stringify({
|
||||
success: false,
|
||||
error: {
|
||||
name: error.name,
|
||||
message: error.message,
|
||||
stack: error.stack ? error.stack.split(/\s+at\s+/).slice(1) : []
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ export default class JSONResponseFactory extends ResponseFactory {
|
||||
}
|
||||
|
||||
public async write(request: Request): Promise<Request> {
|
||||
request.response.headers.set('Content-Type', 'application/json')
|
||||
request.response.body = JSON.stringify(this.value)
|
||||
return request
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import AppClass from '../../lifecycle/AppClass.ts'
|
||||
import {Route, RouteParameters} from './Route.ts'
|
||||
import {RouteHandlers} from '../../unit/Routing.ts'
|
||||
|
||||
export default class ActivatedRoute extends AppClass {
|
||||
public readonly params: RouteParameters
|
||||
@@ -7,6 +8,7 @@ export default class ActivatedRoute extends AppClass {
|
||||
constructor(
|
||||
public readonly incoming: string,
|
||||
public readonly route: Route,
|
||||
public readonly handlers: RouteHandlers | undefined,
|
||||
) {
|
||||
super()
|
||||
this.params = route.build_parameters(incoming)
|
||||
|
||||
Reference in New Issue
Block a user