UNPKG

4.5 kBJavaScriptView Raw
1// @flow
2
3import type { SubrequestsTree } from '../types/BlueprintManager';
4import type { RequestorInterface } from '../types/Requestor';
5import type { Response } from '../types/Responses';
6
7const JsonPathReplacer = require('./JsonPathReplacer');
8
9/**
10 * @classdesc
11 * Handles all the sequential and parallel requests.
12 *
13 * @class SubrequestsManager
14 */
15module.exports = class SubrequestsManager {
16 /**
17 * Take a request tree and issue the subrequests with the requestor.
18 *
19 * @param {SubrequestsTree} tree
20 * The tree of subrequests.
21 * @param {RequestorInterface} requestor
22 * The wrapper to resolve the requests.
23 *
24 * @return {Promise.<Response[]>}
25 * The responses for the requests.
26 */
27 static request(tree: SubrequestsTree, requestor: RequestorInterface): Promise<Array<Response>> {
28 // Loop through all sequential requests and merge them.
29 return this._processBatchesSequence(tree, requestor);
30 }
31
32 /**
33 * Takes a batch sequence and replaces everything that needs replacing.
34 *
35 * @param {SubrequestsTree} tree
36 * The request tree that contains the requesting structure.
37 * @param {RequestorInterface} requestor
38 * The wrapper around the request library to use.
39 * @param {int} _sequence
40 * (internal) The current index in the sequential chain.
41 * @param {Response[]} _responses
42 * (internal) The list of responses accumulated so far.
43 *
44 * @return {Promise.<Response[]>}
45 * A promise of an array of responses when everything has been resolved.
46 *
47 * @private
48 */
49 static _processBatchesSequence(
50 tree: SubrequestsTree,
51 requestor: RequestorInterface,
52 _sequence: number = 0,
53 _responses: Array<Response> = []
54 ): Promise<Array<Response>> {
55 let batch = tree[_sequence];
56 // Perform all the necessary replacements for the elements in the batch.
57 batch = JsonPathReplacer.replaceBatch(batch, _responses);
58 return Promise.all(requestor.requestInParallel(batch))
59 // Turn all the responses from whatever shape the HTTP library uses to the
60 // shape in the Response type.
61 .then(results => this._translateResponsesFromLibFormat(results, requestor))
62 // Link each response with the request that initiated it.
63 .then(this._setRequestIdInResponses.bind(this))
64 // Now that the promise has resolved, issue the new request.
65 .then((results) => {
66 _responses = [..._responses, ...results];
67 // If the last batch was processed then resolve the output. If not
68 // then continue processing batches.
69 _sequence += 1;
70 return _sequence === tree.length
71 ? Promise.resolve(_responses)
72 : this._processBatchesSequence(tree, requestor, _sequence, _responses);
73 });
74 }
75
76 /**
77 * Takes a list of responses in the lib format and turns them into Response.
78 * @param {Array} responses
79 * An array of responses in whatever format the requestor library expects
80 * them.
81 * @param {RequestorInterface} requestor
82 * The requestor that resolved the request.
83 *
84 * @returns {Response[]}
85 * The list of responses in the canonical form.
86 *
87 * @private
88 */
89 static _translateResponsesFromLibFormat(
90 responses: Array<*>,
91 requestor: RequestorInterface
92 ): Array<Response> {
93 return responses.map(response => requestor.translateResponseFromLibFormat(response));
94 }
95
96 /**
97 * Sets the ID of the request that originated the response in Content-ID.
98 *
99 * @param {Response[]} responses
100 * The responses to alter.
101 *
102 * @returns {Response[]}
103 * The altered responses.
104 *
105 * @private
106 */
107 static _setRequestIdInResponses(responses: Array<Response>): Array<Response> {
108 return responses.map((response) => {
109 this._setRequestIdInResponse(response.headers.get('x-subrequest-id'), response);
110 return response;
111 });
112 }
113
114 /**
115 * Puts the request ID in the response so a consumer.
116 *
117 * This way a consumer can know what part of the subrequest was initiated by
118 * what request.
119 *
120 * @param {string} requestId
121 * The content id.
122 * @param {Response} response
123 * The response object we are dealing with.
124 *
125 * @return {void}
126 *
127 * @private
128 */
129 static _setRequestIdInResponse(requestId: ?string, response: Response): void {
130 if (!requestId) {
131 throw new Error(`Unable to find the requestId for response "${JSON.stringify(response)}".`);
132 }
133 response.headers.set('Content-ID', `<${requestId}>`);
134 }
135};