@gravity-ui/gateway 4.7.0 → 4.7.1-alpha.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 +128 -3
- package/{build → dist/commonjs}/components/grpc.d.ts +5 -5
- package/{build → dist/commonjs}/components/grpc.js +94 -84
- package/{build → dist/commonjs}/components/mixed.d.ts +4 -4
- package/{build → dist/commonjs}/components/mixed.js +11 -12
- package/{build → dist/commonjs}/components/rest.d.ts +5 -5
- package/{build → dist/commonjs}/components/rest.js +33 -33
- package/{build → dist/commonjs}/constants.d.ts +2 -2
- package/{build → dist/commonjs}/constants.js +29 -19
- package/{build → dist/commonjs}/index.d.ts +9 -8
- package/{build → dist/commonjs}/index.js +35 -46
- package/{build → dist/commonjs}/models/common.d.ts +12 -7
- package/{build → dist/commonjs}/models/context.d.ts +0 -1
- package/dist/commonjs/package.json +3 -0
- package/dist/commonjs/utils/axios.d.ts +4 -0
- package/{build → dist/commonjs}/utils/axios.js +3 -4
- package/{build → dist/commonjs}/utils/common.d.ts +4 -4
- package/{build → dist/commonjs}/utils/common.js +8 -8
- package/{build → dist/commonjs}/utils/create-context-api.d.ts +2 -2
- package/{build → dist/commonjs}/utils/create-context-api.js +5 -6
- package/{build → dist/commonjs}/utils/grpc-reflection.js +15 -35
- package/{build → dist/commonjs}/utils/grpc.d.ts +1 -1
- package/{build → dist/commonjs}/utils/grpc.js +10 -11
- package/dist/commonjs/utils/overrideEndpoints/index.d.ts +2 -0
- package/dist/commonjs/utils/overrideEndpoints/index.js +4 -0
- package/{build → dist/commonjs}/utils/overrideEndpoints/overrideEndpoints.d.ts +1 -1
- package/{build → dist/commonjs}/utils/overrideEndpoints/overrideEndpoints.js +1 -2
- package/dist/commonjs/utils/package-root.d.ts +1 -0
- package/dist/commonjs/utils/package-root.js +44 -0
- package/{build → dist/commonjs}/utils/parse-error.d.ts +5 -5
- package/{build → dist/commonjs}/utils/parse-error.js +19 -19
- package/{build → dist/commonjs}/utils/proto-path-resolver.d.ts +1 -1
- package/{build → dist/commonjs}/utils/proto-path-resolver.js +24 -15
- package/{build → dist/commonjs}/utils/redact-sensitive-headers.d.ts +1 -2
- package/{build → dist/commonjs}/utils/redact-sensitive-headers.js +1 -2
- package/dist/commonjs/utils/source-dir.d.ts +1 -0
- package/dist/commonjs/utils/source-dir.js +41 -0
- package/{build → dist/commonjs}/utils/typed-api.d.ts +1 -1
- package/{build → dist/commonjs}/utils/typed-api.js +1 -2
- package/{build → dist/commonjs}/utils/validate.js +6 -10
- package/dist/esm/components/grpc.d.ts +24 -0
- package/dist/esm/components/grpc.js +691 -0
- package/dist/esm/components/mixed.d.ts +11 -0
- package/dist/esm/components/mixed.js +62 -0
- package/dist/esm/components/rest.d.ts +8 -0
- package/dist/esm/components/rest.js +357 -0
- package/dist/esm/constants.d.ts +53 -0
- package/dist/esm/constants.js +82 -0
- package/dist/esm/index.d.ts +13 -0
- package/dist/esm/index.js +274 -0
- package/dist/esm/models/common.d.ts +289 -0
- package/dist/esm/models/common.js +5 -0
- package/dist/esm/models/context.d.ts +22 -0
- package/dist/esm/models/context.js +1 -0
- package/dist/esm/models/error.d.ts +12 -0
- package/dist/esm/models/error.js +1 -0
- package/dist/esm/package.json +3 -0
- package/{build → dist/esm}/utils/axios.d.ts +1 -1
- package/dist/esm/utils/axios.js +24 -0
- package/dist/esm/utils/common.d.ts +16 -0
- package/dist/esm/utils/common.js +48 -0
- package/dist/esm/utils/create-context-api.d.ts +4 -0
- package/dist/esm/utils/create-context-api.js +38 -0
- package/dist/esm/utils/grpc-reflection.d.ts +28 -0
- package/dist/esm/utils/grpc-reflection.js +72 -0
- package/dist/esm/utils/grpc.d.ts +15 -0
- package/dist/esm/utils/grpc.js +72 -0
- package/dist/esm/utils/overrideEndpoints/index.d.ts +2 -0
- package/dist/esm/utils/overrideEndpoints/index.js +2 -0
- package/dist/esm/utils/overrideEndpoints/overrideEndpoints.d.ts +17 -0
- package/dist/esm/utils/overrideEndpoints/overrideEndpoints.js +96 -0
- package/dist/esm/utils/package-root.d.ts +1 -0
- package/dist/esm/utils/package-root.js +8 -0
- package/dist/esm/utils/parse-error.d.ts +30 -0
- package/dist/esm/utils/parse-error.js +214 -0
- package/dist/esm/utils/proto-path-resolver.d.ts +2 -0
- package/dist/esm/utils/proto-path-resolver.js +23 -0
- package/dist/esm/utils/redact-sensitive-headers.d.ts +3 -0
- package/dist/esm/utils/redact-sensitive-headers.js +12 -0
- package/dist/esm/utils/source-dir.d.ts +1 -0
- package/dist/esm/utils/source-dir.js +4 -0
- package/dist/esm/utils/typed-api.d.ts +2 -0
- package/dist/esm/utils/typed-api.js +3 -0
- package/dist/esm/utils/validate.d.ts +4 -0
- package/dist/esm/utils/validate.js +47 -0
- package/package.json +41 -16
- package/build/utils/overrideEndpoints/index.d.ts +0 -2
- package/build/utils/overrideEndpoints/index.js +0 -4
- /package/bin/{patch.js → patch.cjs} +0 -0
- /package/{build → dist/commonjs}/models/common.js +0 -0
- /package/{build → dist/commonjs}/models/context.js +0 -0
- /package/{build → dist/commonjs}/models/error.d.ts +0 -0
- /package/{build → dist/commonjs}/models/error.js +0 -0
- /package/{build → dist/commonjs}/utils/grpc-reflection.d.ts +0 -0
- /package/{build → dist/commonjs}/utils/validate.d.ts +0 -0
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ A flexible and powerful Express controller for working with REST and gRPC APIs i
|
|
|
16
16
|
- [Error Handling](#error-handling)
|
|
17
17
|
- [gRPC Reflection](#grpc-reflection-for-grpc-actions)
|
|
18
18
|
- [Retryable Errors](#retryable-errors)
|
|
19
|
+
- [Request Cancellation](#request-cancellation)
|
|
20
|
+
- [Response Content Type Validation](#response-content-type-validation)
|
|
19
21
|
- [Development](#development)
|
|
20
22
|
- [Running Tests](#running-tests)
|
|
21
23
|
- [Contributing](#contributing)
|
|
@@ -72,11 +74,14 @@ interface Stats {
|
|
|
72
74
|
action: string;
|
|
73
75
|
restStatus: number;
|
|
74
76
|
grpcStatus?: number;
|
|
77
|
+
responseSize: number;
|
|
75
78
|
requestId: string;
|
|
76
79
|
requestTime: number;
|
|
77
80
|
requestMethod: string;
|
|
78
81
|
requestUrl: string;
|
|
79
82
|
timestamp: number;
|
|
83
|
+
userId?: string;
|
|
84
|
+
traceId: string;
|
|
80
85
|
}
|
|
81
86
|
|
|
82
87
|
type SendStats = (
|
|
@@ -180,7 +185,7 @@ interface GatewayConfig {
|
|
|
180
185
|
|
|
181
186
|
// When passing a boolean value, it enables/disables debug headers in the response to the request.
|
|
182
187
|
// For unary requests to gRPC backends, debug headers will include information from the trailing metadata returned by the backend.
|
|
183
|
-
withDebugHeaders?: boolean;
|
|
188
|
+
withDebugHeaders?: boolean | ((req: Request, res: Response) => boolean);
|
|
184
189
|
|
|
185
190
|
// Validation schema for parameters used when no schema is present in the action.
|
|
186
191
|
// You can use DEFAULT_VALIDATION_SCHEMA from lib/constants.ts.
|
|
@@ -210,6 +215,9 @@ interface GatewayConfig {
|
|
|
210
215
|
|
|
211
216
|
// Error constructor for handling errors
|
|
212
217
|
ErrorConstructor: AppErrorConstructor;
|
|
218
|
+
|
|
219
|
+
// Axios interceptors configuration
|
|
220
|
+
axiosInterceptors?: AxiosInterceptorsConfig;
|
|
213
221
|
}
|
|
214
222
|
```
|
|
215
223
|
|
|
@@ -218,8 +226,9 @@ interface GatewayConfig {
|
|
|
218
226
|
`GatewayConfig.proxyHeaders` is an optional method that allows setting headers for requests at the entire `gateway` level:
|
|
219
227
|
|
|
220
228
|
```javascript
|
|
221
|
-
const proxyHeaders = (headers, actionType,
|
|
229
|
+
const proxyHeaders = (headers, actionType, extra) => {
|
|
222
230
|
const normalizedHeaders = {...headers};
|
|
231
|
+
const {service, action, protopath, protokey} = extra;
|
|
223
232
|
|
|
224
233
|
if (actionType === 'rest' && service === 'mail') {
|
|
225
234
|
normalizedHeaders['x-mail-service-action'] = action;
|
|
@@ -234,6 +243,13 @@ const {controller: gatewayController} = getGatewayControllers(
|
|
|
234
243
|
);
|
|
235
244
|
```
|
|
236
245
|
|
|
246
|
+
The `extra` parameter contains additional information about the request:
|
|
247
|
+
|
|
248
|
+
- `service`: The service name
|
|
249
|
+
- `action`: The action name
|
|
250
|
+
- `protopath`: The proto path (for gRPC actions)
|
|
251
|
+
- `protokey`: The proto key (for gRPC actions)
|
|
252
|
+
|
|
237
253
|
You can set headers for a specific action using `ApiServiceBaseActionConfig.proxyHeaders`:
|
|
238
254
|
|
|
239
255
|
```javascript
|
|
@@ -321,6 +337,8 @@ interface ApiActionConfig<Context, TRequestData> {
|
|
|
321
337
|
timeout?: number;
|
|
322
338
|
callback?: (response: TResponseData) => void;
|
|
323
339
|
authArgs?: Record<string, unknown>;
|
|
340
|
+
userId?: string;
|
|
341
|
+
abortSignal?: AbortSignal;
|
|
324
342
|
}
|
|
325
343
|
```
|
|
326
344
|
|
|
@@ -512,7 +530,7 @@ The **default** retry condition for REST-actions includes the following conditio
|
|
|
512
530
|
- Network errors (detected by `axiosRetry.isNetworkError`)
|
|
513
531
|
- Other retryable errors (detected by `axiosRetry.isRetryableError`)
|
|
514
532
|
|
|
515
|
-
You can customize retry behavior
|
|
533
|
+
You can customize retry behavior using the `axiosRetryCondition` config option:
|
|
516
534
|
|
|
517
535
|
```javascript
|
|
518
536
|
const config = {
|
|
@@ -524,6 +542,27 @@ const config = {
|
|
|
524
542
|
};
|
|
525
543
|
```
|
|
526
544
|
|
|
545
|
+
You can also set retry conditions at the action level:
|
|
546
|
+
|
|
547
|
+
```javascript
|
|
548
|
+
const schema = {
|
|
549
|
+
userService: {
|
|
550
|
+
serviceName: 'users',
|
|
551
|
+
endpoints: {...},
|
|
552
|
+
actions: {
|
|
553
|
+
getProfile: {
|
|
554
|
+
path: () => '/profile',
|
|
555
|
+
method: 'GET',
|
|
556
|
+
axiosRetryCondition: (error) => {
|
|
557
|
+
// Custom logic for this specific action
|
|
558
|
+
return error.code === 'ECONNRESET';
|
|
559
|
+
},
|
|
560
|
+
},
|
|
561
|
+
},
|
|
562
|
+
},
|
|
563
|
+
};
|
|
564
|
+
```
|
|
565
|
+
|
|
527
566
|
#### gRPC-actions
|
|
528
567
|
|
|
529
568
|
The **default** retry condition for gRPC-actions includes the certain gRPC status codes:
|
|
@@ -545,8 +584,94 @@ const config = {
|
|
|
545
584
|
};
|
|
546
585
|
```
|
|
547
586
|
|
|
587
|
+
The library exports the `isRetryableGrpcError` function that you can use to check if a gRPC error is retryable according to the default conditions:
|
|
588
|
+
|
|
589
|
+
```javascript
|
|
590
|
+
import {isRetryableGrpcError} from '@gravity-ui/gateway';
|
|
591
|
+
|
|
592
|
+
// Use in your custom retry condition
|
|
593
|
+
const customGrpcRetryCondition = (error) => {
|
|
594
|
+
return isRetryableGrpcError(error) || error.code === 'RESOURCE_EXHAUSTED';
|
|
595
|
+
};
|
|
596
|
+
```
|
|
597
|
+
|
|
548
598
|
For gRPC-requests that fail with `DEADLINE_EXCEEDED`, the service connection is recreated before retrying if config option `grpcRecreateService` is not set to `false`.
|
|
549
599
|
|
|
600
|
+
### Request Cancellation
|
|
601
|
+
|
|
602
|
+
The gateway supports cancelling requests when the client disconnects. This is useful for long-running operations where you want to avoid unnecessary processing if the client is no longer waiting for the response.
|
|
603
|
+
|
|
604
|
+
This feature is enabled by default for exported controller. For API requests, you can pass an `AbortSignal` to cancel the request:
|
|
605
|
+
|
|
606
|
+
```javascript
|
|
607
|
+
const abortController = new AbortController();
|
|
608
|
+
|
|
609
|
+
const result = await gatewayApi.serviceName.actionName({
|
|
610
|
+
authArgs: {token: 'auth-token'},
|
|
611
|
+
requestId: '123',
|
|
612
|
+
headers: {},
|
|
613
|
+
args: {param1: 'value1'},
|
|
614
|
+
ctx: context,
|
|
615
|
+
abortSignal: abortController.signal,
|
|
616
|
+
});
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
You can also control this behavior at the action level using the `abortOnClientDisconnect` option:
|
|
620
|
+
|
|
621
|
+
```javascript
|
|
622
|
+
const schema = {
|
|
623
|
+
userService: {
|
|
624
|
+
serviceName: 'users',
|
|
625
|
+
endpoints: {...},
|
|
626
|
+
actions: {
|
|
627
|
+
longRunningOperation: {
|
|
628
|
+
path: () => '/process',
|
|
629
|
+
method: 'POST',
|
|
630
|
+
abortOnClientDisconnect: true, // Enable cancellation for this action
|
|
631
|
+
},
|
|
632
|
+
},
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
### Response Content Type Validation
|
|
638
|
+
|
|
639
|
+
For REST actions, you can validate the content type of the response to ensure it matches your expectations. This is useful for ensuring that the API returns the expected format.
|
|
640
|
+
|
|
641
|
+
You can set the expected content type at the gateway level:
|
|
642
|
+
|
|
643
|
+
```javascript
|
|
644
|
+
const config = {
|
|
645
|
+
// ...other config options
|
|
646
|
+
expectedResponseContentType: 'application/json',
|
|
647
|
+
};
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
Or at the action level:
|
|
651
|
+
|
|
652
|
+
```javascript
|
|
653
|
+
const schema = {
|
|
654
|
+
userService: {
|
|
655
|
+
serviceName: 'users',
|
|
656
|
+
endpoints: {...},
|
|
657
|
+
actions: {
|
|
658
|
+
getProfile: {
|
|
659
|
+
path: () => '/profile',
|
|
660
|
+
method: 'GET',
|
|
661
|
+
expectedResponseContentType: 'application/json',
|
|
662
|
+
},
|
|
663
|
+
getDocument: {
|
|
664
|
+
path: () => '/document',
|
|
665
|
+
method: 'GET',
|
|
666
|
+
expectedResponseContentType: ['application/pdf', 'application/octet-stream'],
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
};
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
You can specify either a single content type or an array of acceptable content types. If the response content type doesn't match any of the expected types, an error will be thrown.
|
|
674
|
+
|
|
550
675
|
### gRPC Reflection for gRPC Actions
|
|
551
676
|
|
|
552
677
|
Instead of using gRPC proto files, you can use gRPC reflection to determine the structure of services and methods.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as grpc from '@grpc/grpc-js';
|
|
2
|
-
import
|
|
2
|
+
import protobufjs from 'protobufjs';
|
|
3
3
|
import type * as descriptor from 'protobufjs/ext/descriptor';
|
|
4
|
-
import { ApiActionConfig, ApiServiceGrpcActionConfig, EndpointsConfig, GatewayApiOptions } from '../models/common';
|
|
5
|
-
import { GatewayContext } from '../models/context';
|
|
6
|
-
import { AppErrorConstructor } from '../models/error';
|
|
4
|
+
import { ApiActionConfig, ApiServiceGrpcActionConfig, EndpointsConfig, GatewayApiOptions } from '../models/common.js';
|
|
5
|
+
import { GatewayContext } from '../models/context.js';
|
|
6
|
+
import { AppErrorConstructor } from '../models/error.js';
|
|
7
7
|
declare module 'protobufjs' {
|
|
8
8
|
interface Root {
|
|
9
9
|
toDescriptor(protoVersion: string): protobufjs.Message<descriptor.IFileDescriptorSet> & descriptor.IFileDescriptorSet;
|
|
@@ -20,5 +20,5 @@ export interface GrpcContext {
|
|
|
20
20
|
}
|
|
21
21
|
export declare function createRoot(includeGrpcPaths?: string[]): protobufjs.Root;
|
|
22
22
|
export declare function getCredentialsMap(caCertificatePath?: string | null): CredentialsMap;
|
|
23
|
-
export
|
|
23
|
+
export declare function createGrpcAction<Context extends GatewayContext>({ root, credentials }: GrpcContext, endpoints: EndpointsConfig | undefined, config: ApiServiceGrpcActionConfig<Context, any, any>, serviceKey: string, actionName: string, options: GatewayApiOptions<Context>, ErrorConstructor: AppErrorConstructor): (actionConfig: ApiActionConfig<Context, any, any>) => Promise<import("../models/common.js").GatewayActionClientStreamResponse<any> | import("../models/common.js").GatewayActionServerStreamResponse<any> | import("../models/common.js").GatewayActionDuplexStreamResponse<any> | import("../models/common.js").GatewayActionUnaryResponse<any>>;
|
|
24
24
|
export {};
|