SDK implementing work with REST/GRPC APIs
npm install --save-dev @gravity-ui/sdkYou need to import sdkFactory and Schema, and create an instance of the class.
If the schema is not divided into scopes:
import sdkFactory from '@gravity-ui/sdk';
import type Schema from '<schemas package>';
const config = {
csrfToken: 'secret-token',
endpoint: '/gateway',
};
const sdk = sdkFactory<{root: typeof Schema}>(config);If the schema is divided into scopes:
import sdkFactory from '@gravity-ui/sdk';
import type Schema from '<schemas package>';
import type LocalSchema from '../../shared/schemas';
const config = {
csrfToken: 'secret-token',
endpoint: '/gateway',
};
const sdk = sdkFactory<{root: typeof Schema; local: typeof LocalSchema}>(config);Structure of config:
import {AxiosRequestConfig} from 'axios';
interface SdkConfig {
// Custom Axios settings
axiosConfig?: AxiosRequestConfig;
// CSRF-token
csrfToken?: string;
// The endpoint to which the request from the client will be sent. By default, "/api" is used
endpoint?: string;
// Custom error handler. If the configuration is not specified, the default one is used
handleRequestError?: (error: unknown) => any;
}In the code, the invocation of the SDK method looks like this:
sdk.<scope>.<service>.<action>(data, options); // => returns a CancelablePromiseIf the default endpoint value /api is specified, the full request path will look like this:
/api/:scope/:service/:action
There is a special scope called root. Its methods can be called without explicitly specifying the scope.
The following calls are equivalent:
sdk.root.<service>.<action>(data, options);
sdk.<service>.<action>(data, options);
But the full request path will always include the scope:
/api/root/:service/:action
Structure of options:
interface SdkOptions {
// Request identifier. The previous request with the same identifier will be canceled
concurrentId?: string;
// Ability to specify a specific number of retries for certain endpoints. By default, the number of retries is 0
retries?: number;
// Ability to specify a specific timeout for certain endpoints.
// By default, the configuration is taken from axiosConfig or set to 60 seconds
timeout?: number;
// Ability to specify specific headers when making a call
headers?: Record<string, unknown>;
// Abort the request, including a response stream that is being read
signal?: AbortSignal;
}With stream: true the request goes through the axios fetch adapter, and the promise resolves with the response body as a ReadableStream<Uint8Array> as soon as the headers arrive. The gateway action must stream its response, e.g. a REST action with responseType: 'stream'.
const stream = await sdk.<scope>.<service>.<action>(data, {stream: true, signal});
const reader = stream.pipeThrough(new TextDecoderStream()).getReader();
for (let chunk = await reader.read(); !chunk.done; chunk = await reader.read()) {
console.log(chunk.value);
}The timeout keeps running until the stream ends, so stream requests have no timeout unless timeout is passed. Once the response headers arrive, cancel() and concurrentId no longer affect the request: stop the stream with signal or reader.cancel(). Gateway errors are read from the body and rejected as usual; only signal aborts reading an error body.
Through the sdk, you have the ability to make calls to external methods that are not defined in the schemas. Such a call looks like this:
sdk(config, options);
The argument config has the type AxiosRequestConfig, and the argument options has the type SdkOptions described above.
For the convenience of creating cancelable promises, the package exports a class called CancellablePromise(promise: Promise, cancel: () => void).
Allows setting the user's language, which will be passed to all invoked endpoints through a special accept-language header.
Allows setting base headers that will be passed to all invoked endpoints.