@gravity-ui/gateway 2.2.0 → 2.4.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/README.md CHANGED
@@ -72,6 +72,7 @@ type ProxyHeadersFunction = (
72
72
  type: ControllerType,
73
73
  ) => IncomingHttpHeaders;
74
74
  type ProxyHeaders = string[] | ProxyHeadersFunction;
75
+ type ResponseContentType = AxiosResponse['headers']['Content-Type'];
75
76
 
76
77
  interface GatewayConfig {
77
78
  // Gateway Installation (external/internal/...). If the configuration is not provided, it is determined from process.env.APP_INSTALLATION.
@@ -119,7 +120,7 @@ interface GatewayConfig {
119
120
  // Configuration for automatic connection re-establishment upon connection error through L3 load balancer (default is true).
120
121
  grpcRecreateService?: boolean;
121
122
  // Enable verification of response contentType header. Actual only for REST actions. This value can be set / redefined the in action confg.
122
- expectedResponseContentType?: AxiosResponse['headers']['Content-Type'];
123
+ expectedResponseContentType?: ResponseContentType | ResponseContentType[];
123
124
  }
124
125
  ```
125
126
 
@@ -426,6 +426,16 @@ function createGrpcAction({ root, credentials }, endpoints, config, serviceKey,
426
426
  if ('protoPath' in config) {
427
427
  debugHeaders['x-api-request-protopath'] = config.protoPath;
428
428
  }
429
+ if (typeof options.proxyDebugHeaders === 'function') {
430
+ Object.assign(debugHeaders, options.proxyDebugHeaders(Object.assign({}, headers), 'grpc'));
431
+ }
432
+ else if (Array.isArray(options.proxyDebugHeaders)) {
433
+ for (const headerName of options.proxyDebugHeaders) {
434
+ if (headers[headerName] !== undefined) {
435
+ debugHeaders[`x-gateway-${headerName}`] = headers[headerName];
436
+ }
437
+ }
438
+ }
429
439
  ctx.log('Initiating request', { debugHeaders: (0, common_2.sanitizeDebugHeaders)(debugHeaders) });
430
440
  const sendStats = (status, data) => {
431
441
  if (options === null || options === void 0 ? void 0 : options.sendStats) {
@@ -184,6 +184,16 @@ function createRestAction(endpoints, config, serviceKey, actionName, options, Er
184
184
  if (headers['content-type']) {
185
185
  debugHeaders['x-api-content-type'] = headers['content-type'];
186
186
  }
187
+ if (typeof options.proxyDebugHeaders === 'function') {
188
+ Object.assign(debugHeaders, options.proxyDebugHeaders(Object.assign({}, requestHeaders), 'rest'));
189
+ }
190
+ else if (Array.isArray(options.proxyDebugHeaders)) {
191
+ for (const headerName of options.proxyDebugHeaders) {
192
+ if (headers[headerName] !== undefined) {
193
+ debugHeaders[`x-gateway-${headerName}`] = headers[headerName];
194
+ }
195
+ }
196
+ }
187
197
  const startRequestTime = Date.now();
188
198
  let axiosClient = defaultAxiosClient;
189
199
  if (actionConfig.timeout || endpointAxiosConfig) {
@@ -225,26 +235,34 @@ function createRestAction(endpoints, config, serviceKey, actionName, options, Er
225
235
  requestData.requestTime = endRequestTime - startRequestTime;
226
236
  const actualResponseContentType = (_f = response.headers) === null || _f === void 0 ? void 0 : _f['Content-Type'];
227
237
  const expectedResponseContentType = config.expectedResponseContentType || options.expectedResponseContentType;
228
- if (actualResponseContentType &&
229
- expectedResponseContentType &&
230
- actualResponseContentType !== expectedResponseContentType) {
231
- ctx.log('Invalid response content type', {
232
- expectedResponseContentType,
233
- actualResponseContentType,
234
- });
235
- ctx.end();
236
- return Promise.reject({
237
- error: {
238
- status: 415,
239
- message: 'Response content type validation failed',
240
- code: 'INVALID_RESPONSE_CONTENT_TYPE',
241
- details: {
242
- title: 'Invalid response content type',
243
- description: `Expected to get ${expectedResponseContentType} but got ${actualResponseContentType}`,
238
+ if (actualResponseContentType && expectedResponseContentType) {
239
+ let isInvalidResponseContentType;
240
+ if (Array.isArray(expectedResponseContentType)) {
241
+ isInvalidResponseContentType = !expectedResponseContentType.includes(String(actualResponseContentType));
242
+ }
243
+ else {
244
+ isInvalidResponseContentType =
245
+ expectedResponseContentType !== actualResponseContentType;
246
+ }
247
+ if (isInvalidResponseContentType) {
248
+ ctx.log('Invalid response content type', {
249
+ expectedResponseContentType,
250
+ actualResponseContentType,
251
+ });
252
+ ctx.end();
253
+ return Promise.reject({
254
+ error: {
255
+ status: 415,
256
+ message: 'Response content type validation failed',
257
+ code: 'INVALID_RESPONSE_CONTENT_TYPE',
258
+ details: {
259
+ title: 'Invalid response content type',
260
+ description: `Expected to get ${expectedResponseContentType} but got ${actualResponseContentType}`,
261
+ },
244
262
  },
245
- },
246
- debugHeaders,
247
- });
263
+ debugHeaders,
264
+ });
265
+ }
248
266
  }
249
267
  if (config.transformResponseData) {
250
268
  try {
package/build/index.js CHANGED
@@ -75,6 +75,7 @@ function createApiAction(schema, config, serviceKey, actionName, api, grpcContex
75
75
  timeout: config.timeout,
76
76
  sendStats: config.sendStats,
77
77
  proxyHeaders: config.proxyHeaders,
78
+ proxyDebugHeaders: config.proxyDebugHeaders,
78
79
  axiosConfig: config.axiosConfig,
79
80
  validationSchema: config.validationSchema,
80
81
  encodePathArgs: config.encodePathArgs,
@@ -87,6 +88,7 @@ function createApiAction(schema, config, serviceKey, actionName, api, grpcContex
87
88
  timeout: config.timeout,
88
89
  sendStats: config.sendStats,
89
90
  proxyHeaders: config.proxyHeaders,
91
+ proxyDebugHeaders: config.proxyDebugHeaders,
90
92
  grpcOptions: config.grpcOptions,
91
93
  grpcRecreateService,
92
94
  getAuthHeaders: config.getAuthHeaders,
@@ -65,12 +65,13 @@ export type ProxyHeaders = string[] | ProxyHeadersFunction;
65
65
  export type ProxyResponseHeadersFunction = (headers: Headers, type: ControllerType) => Headers;
66
66
  export type ProxyResponseHeaders = string[] | ProxyResponseHeadersFunction;
67
67
  export type GetAuthHeadersParams<AuthArgs = Record<string, unknown>> = {
68
- actionType: 'rest' | 'grpc';
68
+ actionType: ControllerType;
69
69
  serviceName: string;
70
70
  requestHeaders: Headers;
71
71
  authArgs: AuthArgs | undefined;
72
72
  };
73
73
  export type GetAuthHeaders<AuthArgs = Record<string, unknown>> = (params: GetAuthHeadersParams<AuthArgs>) => Record<string, string> | undefined;
74
+ export type ResponseContentType = AxiosResponse['headers']['Content-Type'];
74
75
  export interface GatewayApiOptions<Context extends GatewayContext> {
75
76
  serviceName: string;
76
77
  timeout?: number;
@@ -79,9 +80,10 @@ export interface GatewayApiOptions<Context extends GatewayContext> {
79
80
  grpcRecreateService?: boolean;
80
81
  axiosConfig?: AxiosRequestConfig;
81
82
  proxyHeaders?: ProxyHeaders;
83
+ proxyDebugHeaders?: ProxyHeaders;
82
84
  validationSchema?: object;
83
85
  encodePathArgs?: boolean;
84
- expectedResponseContentType?: AxiosResponse['headers']['Content-Type'];
86
+ expectedResponseContentType?: ResponseContentType | ResponseContentType[];
85
87
  getAuthHeaders: GetAuthHeaders;
86
88
  }
87
89
  export interface ParamsOutput {
@@ -125,7 +127,7 @@ export interface ApiServiceRestActionConfig<Context extends GatewayContext, TOut
125
127
  path: (args: TParams) => string;
126
128
  paramsSerializer?: AxiosRequestConfig['paramsSerializer'];
127
129
  responseType?: AxiosRequestConfig['responseType'];
128
- expectedResponseContentType?: AxiosResponse['headers']['Content-Type'];
130
+ expectedResponseContentType?: ResponseContentType | ResponseContentType[];
129
131
  maxRedirects?: number;
130
132
  }
131
133
  export interface ApiServiceBaseGrpcActionConfig<Context extends GatewayContext, TOutput, TParams = undefined, TTransformed = TOutput> extends ApiServiceBaseActionConfig<Context, TOutput, TParams, TTransformed> {
@@ -238,7 +240,8 @@ export interface GatewayConfig<Context extends GatewayContext, Req extends Gatew
238
240
  includeProtoRoots?: string[];
239
241
  caCertificatePath: string | null;
240
242
  proxyHeaders: ProxyHeaders;
241
- withDebugHeaders: boolean | ((req: Req, res: Res) => boolean);
243
+ proxyDebugHeaders?: ProxyHeaders;
244
+ withDebugHeaders?: boolean | ((req: Req, res: Res) => boolean);
242
245
  validationSchema?: object;
243
246
  encodePathArgs?: boolean;
244
247
  getAuthArgs: (req: Req, res: Res) => Record<string, unknown> | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/gateway",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "main": "build/index.js",