@tramvai/module-http-client 2.21.0 → 2.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.es.js +25 -23
- package/lib/index.js +24 -22
- package/package.json +14 -11
- package/tests.d.ts +13 -0
- package/tests.js +359 -0
package/lib/index.es.js
CHANGED
|
@@ -14,7 +14,8 @@ import find from '@tinkoff/utils/array/find';
|
|
|
14
14
|
import { BaseHttpClient } from '@tramvai/http-client';
|
|
15
15
|
export * from '@tramvai/http-client';
|
|
16
16
|
import { getPapiParameters } from '@tramvai/papi';
|
|
17
|
-
import { REQUEST, RESPONSE } from '@tramvai/module-common';
|
|
17
|
+
import { REQUEST, RESPONSE, FASTIFY_REQUEST, FASTIFY_RESPONSE } from '@tramvai/module-common';
|
|
18
|
+
import { PAPI_EXECUTOR } from '@tramvai/tokens-server-private';
|
|
18
19
|
|
|
19
20
|
const fillHeaderIp = ({ requestManager, }) => {
|
|
20
21
|
if (!requestManager) {
|
|
@@ -132,34 +133,35 @@ class PapiService extends BaseHttpClient {
|
|
|
132
133
|
this.di = di;
|
|
133
134
|
}
|
|
134
135
|
async request({ path, query, body }) {
|
|
135
|
-
var _a;
|
|
136
136
|
const papiRoute = find((papi) => getPapiParameters(papi).path === `/${path}`, this.papi);
|
|
137
137
|
if (!papiRoute) {
|
|
138
138
|
throw new Error(`papi handler '${path}' not found`);
|
|
139
139
|
}
|
|
140
|
-
|
|
141
|
-
let rootDeps = {};
|
|
142
|
-
if (papi.rootDeps) {
|
|
143
|
-
rootDeps = this.di.getOfDeps(papi.rootDeps);
|
|
144
|
-
rootDeps = papi.mapRootDeps ? papi.mapRootDeps(rootDeps) : rootDeps;
|
|
145
|
-
}
|
|
146
|
-
const childDI = createChildContainer(this.di);
|
|
140
|
+
getPapiParameters(papiRoute);
|
|
147
141
|
const req = { headers: { host: 'localhost' }, cookies: {}, query, body };
|
|
148
142
|
const res = {};
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
143
|
+
const fastifyReq = { raw: req };
|
|
144
|
+
const fastifyRes = { raw: res };
|
|
145
|
+
const childDi = createChildContainer(this.di, [
|
|
146
|
+
{
|
|
147
|
+
provide: REQUEST,
|
|
148
|
+
useValue: req,
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
provide: RESPONSE,
|
|
152
|
+
useValue: res,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
provide: FASTIFY_REQUEST,
|
|
156
|
+
useValue: fastifyReq,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
provide: FASTIFY_RESPONSE,
|
|
160
|
+
useValue: fastifyRes,
|
|
161
|
+
},
|
|
162
|
+
]);
|
|
163
|
+
const papiExecutor = childDi.get(PAPI_EXECUTOR);
|
|
164
|
+
const payload = await papiExecutor(papiRoute);
|
|
163
165
|
return { payload, status: 200, headers: {} };
|
|
164
166
|
}
|
|
165
167
|
}
|
package/lib/index.js
CHANGED
|
@@ -17,6 +17,7 @@ var find = require('@tinkoff/utils/array/find');
|
|
|
17
17
|
var httpClient = require('@tramvai/http-client');
|
|
18
18
|
var papi = require('@tramvai/papi');
|
|
19
19
|
var moduleCommon = require('@tramvai/module-common');
|
|
20
|
+
var tokensServerPrivate = require('@tramvai/tokens-server-private');
|
|
20
21
|
|
|
21
22
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
22
23
|
|
|
@@ -143,34 +144,35 @@ class PapiService extends httpClient.BaseHttpClient {
|
|
|
143
144
|
this.di = di;
|
|
144
145
|
}
|
|
145
146
|
async request({ path, query, body }) {
|
|
146
|
-
var _a;
|
|
147
147
|
const papiRoute = find__default["default"]((papi$1) => papi.getPapiParameters(papi$1).path === `/${path}`, this.papi);
|
|
148
148
|
if (!papiRoute) {
|
|
149
149
|
throw new Error(`papi handler '${path}' not found`);
|
|
150
150
|
}
|
|
151
|
-
|
|
152
|
-
let rootDeps = {};
|
|
153
|
-
if (papi$1.rootDeps) {
|
|
154
|
-
rootDeps = this.di.getOfDeps(papi$1.rootDeps);
|
|
155
|
-
rootDeps = papi$1.mapRootDeps ? papi$1.mapRootDeps(rootDeps) : rootDeps;
|
|
156
|
-
}
|
|
157
|
-
const childDI = dippy.createChildContainer(this.di);
|
|
151
|
+
papi.getPapiParameters(papiRoute);
|
|
158
152
|
const req = { headers: { host: 'localhost' }, cookies: {}, query, body };
|
|
159
153
|
const res = {};
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
154
|
+
const fastifyReq = { raw: req };
|
|
155
|
+
const fastifyRes = { raw: res };
|
|
156
|
+
const childDi = dippy.createChildContainer(this.di, [
|
|
157
|
+
{
|
|
158
|
+
provide: moduleCommon.REQUEST,
|
|
159
|
+
useValue: req,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
provide: moduleCommon.RESPONSE,
|
|
163
|
+
useValue: res,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
provide: moduleCommon.FASTIFY_REQUEST,
|
|
167
|
+
useValue: fastifyReq,
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
provide: moduleCommon.FASTIFY_RESPONSE,
|
|
171
|
+
useValue: fastifyRes,
|
|
172
|
+
},
|
|
173
|
+
]);
|
|
174
|
+
const papiExecutor = childDi.get(tokensServerPrivate.PAPI_EXECUTOR);
|
|
175
|
+
const payload = await papiExecutor(papiRoute);
|
|
174
176
|
return { payload, status: 200, headers: {} };
|
|
175
177
|
}
|
|
176
178
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-http-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.24.0",
|
|
4
4
|
"initialVersion": "0.58.99",
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"./lib/index.es.js": "./lib/index.browser.js"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
|
-
"lib"
|
|
14
|
+
"lib",
|
|
15
|
+
"tests.js",
|
|
16
|
+
"tests.d.ts"
|
|
15
17
|
],
|
|
16
18
|
"sideEffects": false,
|
|
17
19
|
"repository": {
|
|
@@ -25,10 +27,11 @@
|
|
|
25
27
|
},
|
|
26
28
|
"dependencies": {
|
|
27
29
|
"@tramvai/http-client": "0.2.2",
|
|
28
|
-
"@tramvai/tinkoff-request-http-client-adapter": "0.9.
|
|
29
|
-
"@tramvai/tokens-http-client": "2.
|
|
30
|
-
"@tramvai/tokens-common": "2.
|
|
31
|
-
"@tramvai/tokens-server": "2.
|
|
30
|
+
"@tramvai/tinkoff-request-http-client-adapter": "0.9.57",
|
|
31
|
+
"@tramvai/tokens-http-client": "2.24.0",
|
|
32
|
+
"@tramvai/tokens-common": "2.24.0",
|
|
33
|
+
"@tramvai/tokens-server": "2.24.0",
|
|
34
|
+
"@tramvai/tokens-server-private": "2.24.0"
|
|
32
35
|
},
|
|
33
36
|
"devDependencies": {
|
|
34
37
|
"@tinkoff/request-core": "^0.9.2",
|
|
@@ -36,11 +39,11 @@
|
|
|
36
39
|
},
|
|
37
40
|
"peerDependencies": {
|
|
38
41
|
"@tinkoff/utils": "^2.1.2",
|
|
39
|
-
"@tramvai/core": "2.
|
|
40
|
-
"@tramvai/module-common": "2.
|
|
41
|
-
"@tramvai/papi": "2.
|
|
42
|
-
"@tramvai/test-helpers": "2.
|
|
43
|
-
"@tramvai/test-mocks": "2.
|
|
42
|
+
"@tramvai/core": "2.24.0",
|
|
43
|
+
"@tramvai/module-common": "2.24.0",
|
|
44
|
+
"@tramvai/papi": "2.24.0",
|
|
45
|
+
"@tramvai/test-helpers": "2.24.0",
|
|
46
|
+
"@tramvai/test-mocks": "2.24.0",
|
|
44
47
|
"@tinkoff/dippy": "0.8.2",
|
|
45
48
|
"node-fetch": "^2.6.1",
|
|
46
49
|
"tslib": "^2.0.3"
|
package/tests.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="jest" />
|
|
2
|
+
import { getDiWrapper } from "@tramvai/test-helpers";
|
|
3
|
+
import { createMockEnvManager } from "@tramvai/test-mocks";
|
|
4
|
+
type Options = Parameters<typeof getDiWrapper>[0] & {
|
|
5
|
+
env?: Parameters<typeof createMockEnvManager>[0];
|
|
6
|
+
};
|
|
7
|
+
declare const testApi: (options: Options) => {
|
|
8
|
+
di: import("@tinkoff/dippy").Container;
|
|
9
|
+
fetchMock: jest.Mock<any, unknown[]>;
|
|
10
|
+
mockJsonResponse: (body: Record<string, any>, init?: ResponseInit) => Promise<void>;
|
|
11
|
+
clearCaches: () => void;
|
|
12
|
+
};
|
|
13
|
+
export { testApi };
|
package/tests.js
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var fetch = require('node-fetch');
|
|
6
|
+
var core = require('@tramvai/core');
|
|
7
|
+
var tokensCommon = require('@tramvai/tokens-common');
|
|
8
|
+
var testHelpers = require('@tramvai/test-helpers');
|
|
9
|
+
var testMocks = require('@tramvai/test-mocks');
|
|
10
|
+
var dippy = require('@tinkoff/dippy');
|
|
11
|
+
var tokensHttpClient = require('@tramvai/tokens-http-client');
|
|
12
|
+
var isNil = require('@tinkoff/utils/is/nil');
|
|
13
|
+
var compose = require('@tinkoff/utils/function/compose');
|
|
14
|
+
var tinkoffRequestHttpClientAdapter = require('@tramvai/tinkoff-request-http-client-adapter');
|
|
15
|
+
var identity = require('@tinkoff/utils/function/identity');
|
|
16
|
+
var flatten = require('@tinkoff/utils/array/flatten');
|
|
17
|
+
var pick = require('@tinkoff/utils/object/pick');
|
|
18
|
+
var tokensServer = require('@tramvai/tokens-server');
|
|
19
|
+
var find = require('@tinkoff/utils/array/find');
|
|
20
|
+
var httpClient = require('@tramvai/http-client');
|
|
21
|
+
var papi = require('@tramvai/papi');
|
|
22
|
+
var moduleCommon = require('@tramvai/module-common');
|
|
23
|
+
var tokensServerPrivate = require('@tramvai/tokens-server-private');
|
|
24
|
+
|
|
25
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
26
|
+
|
|
27
|
+
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
|
|
28
|
+
var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
|
|
29
|
+
var compose__default = /*#__PURE__*/_interopDefaultLegacy(compose);
|
|
30
|
+
var identity__default = /*#__PURE__*/_interopDefaultLegacy(identity);
|
|
31
|
+
var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
|
|
32
|
+
var pick__default = /*#__PURE__*/_interopDefaultLegacy(pick);
|
|
33
|
+
var find__default = /*#__PURE__*/_interopDefaultLegacy(find);
|
|
34
|
+
|
|
35
|
+
const fillHeaderIp = ({ requestManager, }) => {
|
|
36
|
+
if (!requestManager) {
|
|
37
|
+
return identity__default["default"];
|
|
38
|
+
}
|
|
39
|
+
return (params) => {
|
|
40
|
+
return {
|
|
41
|
+
...params,
|
|
42
|
+
headers: {
|
|
43
|
+
...params.headers,
|
|
44
|
+
'X-real-ip': requestManager.getClientIp(),
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
const fillHeaders = ({ requestManager, headersList, }) => {
|
|
50
|
+
if (!requestManager) {
|
|
51
|
+
return identity__default["default"];
|
|
52
|
+
}
|
|
53
|
+
const headerNames = flatten__default["default"](headersList !== null && headersList !== void 0 ? headersList : []);
|
|
54
|
+
return (params) => {
|
|
55
|
+
return {
|
|
56
|
+
...params,
|
|
57
|
+
headers: {
|
|
58
|
+
...params.headers,
|
|
59
|
+
...pick__default["default"](headerNames, requestManager.getHeaders()),
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const createUserAgent = ({ appInfo, envManager, }) => {
|
|
66
|
+
const { appName } = appInfo;
|
|
67
|
+
const appVersion = envManager.get('APP_VERSION');
|
|
68
|
+
const appRelease = envManager.get('APP_RELEASE');
|
|
69
|
+
const userAgent = [
|
|
70
|
+
'tramvai',
|
|
71
|
+
appName,
|
|
72
|
+
appVersion && `version ${appVersion}`,
|
|
73
|
+
appRelease && `release ${appRelease}`,
|
|
74
|
+
]
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.join(' ');
|
|
77
|
+
return userAgent;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const environmentDependentOptions = typeof window === 'undefined'
|
|
81
|
+
? {
|
|
82
|
+
defaultTimeout: 2000,
|
|
83
|
+
}
|
|
84
|
+
: {
|
|
85
|
+
defaultTimeout: 30000,
|
|
86
|
+
};
|
|
87
|
+
const httpClientFactory = ({ logger, envManager, appInfo, requestManager, headersList, createCache, makeRequestRegistry, agent, querySerializer, disableCircuitBreaker = false, defaultOptions, commandLineExecutionContext, }) => {
|
|
88
|
+
return (options) => {
|
|
89
|
+
var _a;
|
|
90
|
+
if (!options.name) {
|
|
91
|
+
throw Error(`You need to pass a unique field "name" for the HTTP client instance`);
|
|
92
|
+
}
|
|
93
|
+
const forceDisableCache = envManager.get('HTTP_CLIENT_CACHE_DISABLED');
|
|
94
|
+
const forceDisabledCircuitBreaker = envManager.get('HTTP_CLIENT_CIRCUIT_BREAKER_DISABLED');
|
|
95
|
+
const adapterOptions = tinkoffRequestHttpClientAdapter.mergeOptions(tinkoffRequestHttpClientAdapter.mergeOptions({
|
|
96
|
+
logger,
|
|
97
|
+
agent,
|
|
98
|
+
querySerializer,
|
|
99
|
+
method: 'GET',
|
|
100
|
+
createCache: createCache
|
|
101
|
+
? (cacheOptions) => createCache('memory', cacheOptions)
|
|
102
|
+
: undefined,
|
|
103
|
+
modifyRequest: compose__default["default"](fillHeaderIp({ requestManager }), fillHeaders({ requestManager, headersList })),
|
|
104
|
+
circuitBreakerOptions: {
|
|
105
|
+
failureThreshold: 75,
|
|
106
|
+
minimumFailureCount: 10,
|
|
107
|
+
},
|
|
108
|
+
signal: (_a = commandLineExecutionContext === null || commandLineExecutionContext === void 0 ? void 0 : commandLineExecutionContext()) === null || _a === void 0 ? void 0 : _a.abortSignal,
|
|
109
|
+
...environmentDependentOptions,
|
|
110
|
+
}, defaultOptions !== null && defaultOptions !== void 0 ? defaultOptions : {}), options);
|
|
111
|
+
// по умолчанию, на сервере, библиотека https://github.com/node-fetch/node-fetch
|
|
112
|
+
// отправляет заголовок "User-Agent" вида "node-fetch".
|
|
113
|
+
// для улучшения логов сервисов, в которые делают запросы tramvai приложения,
|
|
114
|
+
// заменяем "User-Agent" на кастомный, содержащий название и версию приложения
|
|
115
|
+
if (typeof window === 'undefined') {
|
|
116
|
+
adapterOptions.headers = {
|
|
117
|
+
'User-Agent': createUserAgent({ appInfo, envManager }),
|
|
118
|
+
...adapterOptions.headers,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (!isNil__default["default"](forceDisableCache)) {
|
|
122
|
+
adapterOptions.disableCache = !!forceDisableCache;
|
|
123
|
+
}
|
|
124
|
+
if (disableCircuitBreaker) {
|
|
125
|
+
adapterOptions.enableCircuitBreaker = false;
|
|
126
|
+
}
|
|
127
|
+
// environment variable in priority over disableCircuitBreaker
|
|
128
|
+
if (!isNil__default["default"](forceDisabledCircuitBreaker)) {
|
|
129
|
+
adapterOptions.enableCircuitBreaker = !forceDisabledCircuitBreaker;
|
|
130
|
+
}
|
|
131
|
+
// кэшируем инстанс @tinkoff/request
|
|
132
|
+
if (!makeRequestRegistry.has(adapterOptions.name)) {
|
|
133
|
+
makeRequestRegistry.set(adapterOptions.name, tinkoffRequestHttpClientAdapter.createTinkoffRequest(adapterOptions));
|
|
134
|
+
}
|
|
135
|
+
const makeRequest = makeRequestRegistry.get(adapterOptions.name);
|
|
136
|
+
const httpClientAdapter = new tinkoffRequestHttpClientAdapter.HttpClientAdapter({
|
|
137
|
+
options: adapterOptions,
|
|
138
|
+
makeRequest,
|
|
139
|
+
});
|
|
140
|
+
return httpClientAdapter;
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
class PapiService extends httpClient.BaseHttpClient {
|
|
145
|
+
constructor({ papi, di }) {
|
|
146
|
+
super();
|
|
147
|
+
this.papi = flatten__default["default"](papi || []);
|
|
148
|
+
this.di = di;
|
|
149
|
+
}
|
|
150
|
+
async request({ path, query, body }) {
|
|
151
|
+
const papiRoute = find__default["default"]((papi$1) => papi.getPapiParameters(papi$1).path === `/${path}`, this.papi);
|
|
152
|
+
if (!papiRoute) {
|
|
153
|
+
throw new Error(`papi handler '${path}' not found`);
|
|
154
|
+
}
|
|
155
|
+
papi.getPapiParameters(papiRoute);
|
|
156
|
+
const req = { headers: { host: 'localhost' }, cookies: {}, query, body };
|
|
157
|
+
const res = {};
|
|
158
|
+
const fastifyReq = { raw: req };
|
|
159
|
+
const fastifyRes = { raw: res };
|
|
160
|
+
const childDi = dippy.createChildContainer(this.di, [
|
|
161
|
+
{
|
|
162
|
+
provide: moduleCommon.REQUEST,
|
|
163
|
+
useValue: req,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
provide: moduleCommon.RESPONSE,
|
|
167
|
+
useValue: res,
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
provide: moduleCommon.FASTIFY_REQUEST,
|
|
171
|
+
useValue: fastifyReq,
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
provide: moduleCommon.FASTIFY_RESPONSE,
|
|
175
|
+
useValue: fastifyRes,
|
|
176
|
+
},
|
|
177
|
+
]);
|
|
178
|
+
const papiExecutor = childDi.get(tokensServerPrivate.PAPI_EXECUTOR);
|
|
179
|
+
const payload = await papiExecutor(papiRoute);
|
|
180
|
+
return { payload, status: 200, headers: {} };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const PapiClientModule = /* @__PURE__ */ core.Module({
|
|
185
|
+
providers: [
|
|
186
|
+
core.provide({
|
|
187
|
+
provide: tokensHttpClient.PAPI_SERVICE,
|
|
188
|
+
scope: core.Scope.SINGLETON,
|
|
189
|
+
useClass: PapiService,
|
|
190
|
+
deps: {
|
|
191
|
+
di: core.DI_TOKEN,
|
|
192
|
+
papi: { token: tokensServer.SERVER_MODULE_PAPI_PUBLIC_ROUTE, optional: true, multi: true },
|
|
193
|
+
},
|
|
194
|
+
}),
|
|
195
|
+
],
|
|
196
|
+
})(class PapiClientModule {
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const createCacheToken = dippy.createToken('httpClient createCache');
|
|
200
|
+
const HttpClientModule = /* @__PURE__ */ core.Module({
|
|
201
|
+
imports: [PapiClientModule],
|
|
202
|
+
providers: [
|
|
203
|
+
core.provide({
|
|
204
|
+
provide: tokensHttpClient.HTTP_CLIENT_FACTORY,
|
|
205
|
+
useFactory: httpClientFactory,
|
|
206
|
+
deps: {
|
|
207
|
+
logger: tokensCommon.LOGGER_TOKEN,
|
|
208
|
+
envManager: tokensCommon.ENV_MANAGER_TOKEN,
|
|
209
|
+
appInfo: core.APP_INFO_TOKEN,
|
|
210
|
+
createCache: createCacheToken,
|
|
211
|
+
makeRequestRegistry: 'makeRequestRegistry',
|
|
212
|
+
requestManager: {
|
|
213
|
+
token: tokensCommon.REQUEST_MANAGER_TOKEN,
|
|
214
|
+
optional: true,
|
|
215
|
+
},
|
|
216
|
+
headersList: {
|
|
217
|
+
token: tokensHttpClient.API_CLIENT_PASS_HEADERS,
|
|
218
|
+
optional: true,
|
|
219
|
+
},
|
|
220
|
+
agent: {
|
|
221
|
+
token: tokensHttpClient.HTTP_CLIENT_AGENT,
|
|
222
|
+
optional: true,
|
|
223
|
+
},
|
|
224
|
+
disableCircuitBreaker: {
|
|
225
|
+
token: tokensHttpClient.DISABLE_CIRCUIT_BREAKER,
|
|
226
|
+
optional: true,
|
|
227
|
+
},
|
|
228
|
+
defaultOptions: {
|
|
229
|
+
token: tokensHttpClient.DEFAULT_HTTP_CLIENT_FACTORY_OPTIONS,
|
|
230
|
+
optional: true,
|
|
231
|
+
},
|
|
232
|
+
commandLineExecutionContext: {
|
|
233
|
+
token: tokensCommon.COMMAND_LINE_EXECUTION_CONTEXT_TOKEN,
|
|
234
|
+
optional: true,
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
}),
|
|
238
|
+
core.provide({
|
|
239
|
+
provide: tokensHttpClient.HTTP_CLIENT,
|
|
240
|
+
useFactory: ({ factory }) => {
|
|
241
|
+
return factory({
|
|
242
|
+
name: 'http-client',
|
|
243
|
+
disableCache: true,
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
deps: {
|
|
247
|
+
factory: tokensHttpClient.HTTP_CLIENT_FACTORY,
|
|
248
|
+
},
|
|
249
|
+
}),
|
|
250
|
+
core.provide({
|
|
251
|
+
provide: tokensCommon.ENV_USED_TOKEN,
|
|
252
|
+
useValue: [
|
|
253
|
+
{ key: 'HTTP_CLIENT_CACHE_DISABLED', optional: true, dehydrate: false },
|
|
254
|
+
{ key: 'HTTP_CLIENT_CIRCUIT_BREAKER_DISABLED', optional: true, dehydrate: false },
|
|
255
|
+
],
|
|
256
|
+
}),
|
|
257
|
+
/**
|
|
258
|
+
* хранилище для экземпляров @tinkoff/request
|
|
259
|
+
*
|
|
260
|
+
* требуется хранить экземпляры в единственном виде,
|
|
261
|
+
* т.к. многие плагины @tinkoff/request после инициализации имеют состояние
|
|
262
|
+
* (cache, circuit breaker), и не будут корректно работать на сервере,
|
|
263
|
+
* если создавать новые экземпляры на Scope.REQUEST
|
|
264
|
+
*/
|
|
265
|
+
core.provide({
|
|
266
|
+
provide: 'makeRequestRegistry',
|
|
267
|
+
scope: core.Scope.SINGLETON,
|
|
268
|
+
useFactory: () => new Map(),
|
|
269
|
+
}),
|
|
270
|
+
/**
|
|
271
|
+
* `CREATE_CACHE_TOKEN` имеет проверку, если токен используется провайдером,
|
|
272
|
+
* который имеет Scope.SINGLETON, то инстанс кэша сохраняется в общее хранилище,
|
|
273
|
+
* и доступен для очистки через `/papi/clear-cache`.
|
|
274
|
+
* Scope.REQUEST игнорируется, т.к. это верная утечка памяти,
|
|
275
|
+
* инстансов кэши было бы неограниченное количество.
|
|
276
|
+
*
|
|
277
|
+
* HTTP клиенты создаются со Scope.REQUEST, но инстансы @tinkoff/request
|
|
278
|
+
* (и соответственно кэшей) создаются только один раз, благодаря `makeRequestRegistry`.
|
|
279
|
+
* это гарантирует отсутствие утечек памяти, поэтому мы обходим проверку
|
|
280
|
+
* на Scope.SINGLETON c помощью обертки `createCacheToken`
|
|
281
|
+
*/
|
|
282
|
+
core.provide({
|
|
283
|
+
provide: createCacheToken,
|
|
284
|
+
scope: core.Scope.SINGLETON,
|
|
285
|
+
useFactory: ({ createCache }) => {
|
|
286
|
+
return createCache;
|
|
287
|
+
},
|
|
288
|
+
deps: {
|
|
289
|
+
createCache: tokensCommon.CREATE_CACHE_TOKEN,
|
|
290
|
+
},
|
|
291
|
+
}),
|
|
292
|
+
core.provide({
|
|
293
|
+
provide: tokensHttpClient.API_CLIENT_PASS_HEADERS,
|
|
294
|
+
useValue: ['x-request-id'],
|
|
295
|
+
}),
|
|
296
|
+
],
|
|
297
|
+
})(class HttpClientModule {
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
jest.mock('node-fetch');
|
|
301
|
+
const { Response } = jest.requireActual('node-fetch');
|
|
302
|
+
const testApi = (options) => {
|
|
303
|
+
const caches = [];
|
|
304
|
+
const { modules = [], providers = [], env } = options;
|
|
305
|
+
const { di } = testHelpers.getDiWrapper({
|
|
306
|
+
di: options.di,
|
|
307
|
+
modules: [HttpClientModule, ...modules],
|
|
308
|
+
providers: [
|
|
309
|
+
core.provide({
|
|
310
|
+
provide: tokensCommon.ENV_MANAGER_TOKEN,
|
|
311
|
+
useValue: testMocks.createMockEnvManager(env),
|
|
312
|
+
}),
|
|
313
|
+
core.provide({
|
|
314
|
+
provide: tokensCommon.LOGGER_TOKEN,
|
|
315
|
+
useValue: testMocks.createMockLogger(),
|
|
316
|
+
}),
|
|
317
|
+
core.provide({
|
|
318
|
+
provide: core.APP_INFO_TOKEN,
|
|
319
|
+
useValue: testMocks.createMockAppInfo(),
|
|
320
|
+
}),
|
|
321
|
+
core.provide({
|
|
322
|
+
provide: tokensCommon.REQUEST_MANAGER_TOKEN,
|
|
323
|
+
useValue: testMocks.createMockRequestManager(),
|
|
324
|
+
}),
|
|
325
|
+
core.provide({
|
|
326
|
+
provide: tokensCommon.CREATE_CACHE_TOKEN,
|
|
327
|
+
useValue: () => {
|
|
328
|
+
const cache = testMocks.createMockCache();
|
|
329
|
+
caches.push(cache);
|
|
330
|
+
return cache;
|
|
331
|
+
},
|
|
332
|
+
}),
|
|
333
|
+
...providers,
|
|
334
|
+
],
|
|
335
|
+
});
|
|
336
|
+
const fetchMock = fetch__default["default"];
|
|
337
|
+
const clearCaches = () => {
|
|
338
|
+
caches.forEach((cache) => cache.clear());
|
|
339
|
+
};
|
|
340
|
+
return {
|
|
341
|
+
di,
|
|
342
|
+
fetchMock,
|
|
343
|
+
mockJsonResponse: async (body, init = {}) => {
|
|
344
|
+
clearCaches();
|
|
345
|
+
const { headers = {} } = init;
|
|
346
|
+
fetchMock.mockImplementation(() => Promise.resolve(new Response(JSON.stringify(body), {
|
|
347
|
+
status: 200,
|
|
348
|
+
...init,
|
|
349
|
+
headers: {
|
|
350
|
+
'content-type': 'application/json',
|
|
351
|
+
...headers,
|
|
352
|
+
},
|
|
353
|
+
})));
|
|
354
|
+
},
|
|
355
|
+
clearCaches,
|
|
356
|
+
};
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
exports.testApi = testApi;
|