From 54fd697f622c73972351f958cf535ec85e71a0b6 Mon Sep 17 00:00:00 2001 From: Yevheniy Oliynyk Date: Sun, 28 May 2023 21:36:57 +0300 Subject: [PATCH] feat: http request timeout option (#271) --- README.md | 15 ++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- src/core/index.ts | 11 +++++++++-- src/core/internal/fetch/fetchClient.ts | 27 +++++++++++++++++++++----- 5 files changed, 49 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2ab3e0d1e..3a6937369 100644 --- a/README.md +++ b/README.md @@ -407,6 +407,21 @@ async function test() { test(); ``` +### Http request timeout + +By default request timeout will vary on http client implementation and/or environment (e.g. `fetch` uses timeout configured by the browser). +But there is an option to set constant value: + +```javascript +const crowdin = require('@crowdin/crowdin-api-client'); + +const credentials = { token: 'token' }; + +const httpRequestTimeout = 60 * 1000; // 60 seconds + +const client = new crowdin.default(credentials, { httpRequestTimeout }); +``` + ## Over-The-Air Content Delivery :dizzy: Recommended for translations delivery to your website or mobile application. diff --git a/package-lock.json b/package-lock.json index e30c4b7b0..d019703b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@crowdin/crowdin-api-client", - "version": "1.23.0", + "version": "1.23.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@crowdin/crowdin-api-client", - "version": "1.23.0", + "version": "1.23.1", "license": "MIT", "dependencies": { "axios": "^1" diff --git a/package.json b/package.json index dcee84aac..1bde77d22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@crowdin/crowdin-api-client", - "version": "1.23.0", + "version": "1.23.1", "description": "JavaScript library for Crowdin API", "main": "out/index.js", "types": "out/index.d.ts", diff --git a/src/core/index.ts b/src/core/index.ts index a9ec5c2b7..6d7cf7980 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -51,6 +51,9 @@ export interface ClientConfig { /** Retry strategy configuration */ retryConfig?: RetryConfig; + + /** Http request timeout in ms */ + httpRequestTimeout?: number; } export interface ResponseList { @@ -228,6 +231,11 @@ export abstract class CrowdinApi { } this.retryService = new RetryService(retryConfig); + if (config?.httpRequestTimeout) { + CrowdinApi.FETCH_INSTANCE.withTimeout(config?.httpRequestTimeout); + CrowdinApi.AXIOS_INSTANCE.defaults.timeout = config?.httpRequestTimeout; + } + this.config = config; } @@ -286,8 +294,7 @@ export abstract class CrowdinApi { return CrowdinApi.AXIOS_INSTANCE; } - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - public withFetchAll(maxLimit?: number) { + public withFetchAll(maxLimit?: number): this { this.fetchAllFlag = true; this.maxLimit = maxLimit; return this; diff --git a/src/core/internal/fetch/fetchClient.ts b/src/core/internal/fetch/fetchClient.ts index 0044a4eb8..8fa1bee1f 100644 --- a/src/core/internal/fetch/fetchClient.ts +++ b/src/core/internal/fetch/fetchClient.ts @@ -14,6 +14,13 @@ export class FetchClient implements HttpClient { private requestIntervalMs = 10; private pendingRequests = 0; + private timeout: number | undefined; + + withTimeout(timeout?: number): this { + this.timeout = timeout; + return this; + } + get(url: string, config?: { headers: Record }): Promise { return this.request(url, 'GET', config); } @@ -52,11 +59,21 @@ export class FetchClient implements HttpClient { } await this.waitInQueue(); - return fetch(url, { - method: method, - headers: config ? config.headers : {}, - body: body, - }) + let request; + const headers = config ? config.headers : {}; + + if (this.timeout) { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), this.timeout); + request = fetch(url, { method, headers, body, signal: controller.signal }).then(res => { + clearTimeout(timeoutId); + return res; + }); + } else { + request = fetch(url, { method, headers, body }); + } + + return request .then(async res => { if (res.status === 204) { return {};