UNPKG

3.31 kBJavaScriptView Raw
1const _ = require('lodash');
2const endResponse = require('./endResponse');
3
4/**
5 * Creates a new request object based on an existing request and some overrides.
6 *
7 * @param {string} path
8 * The route path to execute.
9 * @param {IncomingMessage} originalReq
10 * The original request object.
11 * @param {Object} requestOverrides
12 * Manual overrides for the request.
13 *
14 * @return {Object}
15 * The newly created request object.
16 */
17const createRequest = (path, originalReq, requestOverrides = {}) => {
18 // Clone the original request.
19 const newReq = _.cloneDeep(originalReq);
20 // Delete all private properties since those should be computed.
21 Object.keys(newReq)
22 .filter(key => key[0] === '_')
23 .forEach((key) => {
24 delete newReq[key];
25 });
26 // Apply overrides.
27 Object.keys(requestOverrides)
28 .forEach((key) => {
29 newReq[key] = requestOverrides[key];
30 });
31 // Override the URL.
32 newReq.url = path;
33 newReq.originalUrl = path;
34 // Make sure the request method is uppercase.
35 newReq.method = newReq.method.toUpperCase();
36 newReq.originalMethod = newReq.method;
37
38 return newReq;
39};
40
41/**
42 * Creates a response that other middlewares can interact with.
43 *
44 * @param {ServerResponse} originalRes
45 * The original response.
46 * @param {IncomingMessage} req
47 * The modified request object.
48 * @param {function} callback
49 * Instead of terminating the response as express would normally do upon
50 * calling res.end, we will execute this callback.
51 *
52 * @return {Object}
53 * A response mock that contains the most commonly called response methods.
54 */
55const createResponse = (originalRes, req, callback) => {
56 // Clone the original response.
57 const newRes = _.cloneDeep(originalRes);
58 // Set the modified request object.
59 newRes.req = req;
60
61 // Response termination using our custom callback instead.
62 newRes.end = endResponse(newRes, callback);
63 newRes.send = newRes.end;
64 newRes.write = newRes.end;
65
66 return newRes;
67};
68
69/**
70 * Creates the request and response objects.
71 *
72 * @param {string} path
73 * The route path to execute.
74 * @param {IncomingMessage} req
75 * The original request object.
76 * @param {ServerResponse} res
77 * The original response object.
78 * @param {Object} requestOverrides
79 * Manual overrides for the request.
80 * @param {function} callback
81 * Instead of terminating the response as express would normally do upon
82 * calling res.end, we will execute this callback.
83 *
84 * @return {[IncomingMessage, ServerResponse]}
85 * A tuple containing the request and response objects.
86 */
87const createRequestAndResponse = (path, req, res, requestOverrides, callback) => {
88 callback = _.once(callback);
89 const newRew = createRequest(path, req, requestOverrides);
90 const newRes = createResponse(res, newRew, callback);
91 return [newRew, newRes];
92};
93
94module.exports = (app) => {
95 app.use((req, res, next) => {
96 req.runMiddleware = (path, requestOverrides, callback) => {
97 app.runMiddleware(path, req, res, requestOverrides, callback);
98 };
99 next();
100 });
101
102 // Only add once to the app object.
103 if (app.runMiddleware) {
104 return;
105 }
106
107 app.runMiddleware = (path, req, res, requestOverrides, callback) => {
108 const tuple = createRequestAndResponse(path, req, res, requestOverrides, callback);
109 app(tuple[0], tuple[1]);
110 };
111};