/
sequence.ts
108 lines (101 loc) · 3.48 KB
/
sequence.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: @loopback/core
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
const debug = require('debug')('loopback:core:sequence');
import {ServerRequest, ServerResponse} from 'http';
import {inject} from '@loopback/context';
import {
FindRoute,
InvokeMethod,
LogError,
OperationRetval,
ParsedRequest,
Send,
Reject,
} from './internal-types';
import {parseOperationArgs} from './parser';
import {writeResultToResponse} from './writer';
import {HttpError} from 'http-errors';
/**
* A sequence function is a function implementing a custom
* sequence of actions to handle an incoming request.
*/
export type SequenceFunction = (
sequence: DefaultSequence,
request: ParsedRequest,
response: ServerResponse,
) => Promise<void> | void;
/**
* A sequence handler is a class implementing sequence of actions
* required to handle an incoming request.
*/
export interface SequenceHandler {
/**
* Handle the request by running the configured sequence of actions.
*
* @param request The incoming HTTP request
* @param response The HTTP server response where to write the result
*/
handle(request: ParsedRequest, response: ServerResponse): Promise<void>;
}
/**
* The default implementation of SequenceHandler.
*
* This class implements default Sequence for the LoopBack framework.
* Default sequence is used if user hasn't defined their own Sequence
* for their application.
*
* Sequence constructor() and run() methods are invoked from [[http-handler]]
* when the API request comes in. User defines APIs in their Application
* Controller class.
*
* User can bind their own Sequence to app as shown below
* ```ts
* app.bind('sequence').toClass(MySequence);
* ```
*/
export class DefaultSequence implements SequenceHandler {
/**
* Constructor: Injects findRoute, invokeMethod & logError
* methods as promises.
*
* @param findRoute Finds the appropriate controller method,
* spec and args for invocation
* @param invoke Invokes the method
* @param logError Logs error
*/
constructor(
@inject('sequence.actions.findRoute') protected findRoute: FindRoute,
@inject('sequence.actions.invokeMethod') protected invoke: InvokeMethod,
@inject('sequence.actions.send') public send: Send,
@inject('sequence.actions.reject') public reject: Reject,
) {}
/**
* Runs the default sequence. Given a request and response, running the
* sequence will produce a response or an error.
*
* Default sequence executes these steps
* - Finds the appropriate controller method, swagger spec
* and args for invocation
* - Parses HTTP request to get API argument list
* - Invokes the API which is defined in the Application Controller
* - Writes the result from API into the HTTP response
* - Error is caught and logged using 'logError' if any of the above steps
* in the sequence fails with an error.
* @param req Parsed incoming HTTP request
* @param res HTTP server response with result from Application controller
* method invocation
*/
async handle(req: ParsedRequest, res: ServerResponse) {
try {
const route = this.findRoute(req);
const args = await parseOperationArgs(req, route);
const result = await this.invoke(route, args);
debug('%s result -', route.describe(), result);
this.send(res, result);
} catch (err) {
this.reject(res, req, err);
}
}
}