From 2d34740e79ebe8e9bdba686de3e2302dae7e1c7b Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Bajpai Date: Tue, 19 May 2026 14:03:03 +0530 Subject: [PATCH] feat: configure HTTP timeout via env --- .env.example | 1 + README.md | 2 ++ src/core/fetcher.js | 3 ++- src/discovery/graphql.js | 3 ++- src/discovery/openapi.js | 3 ++- src/utils/httpTimeout.js | 18 ++++++++++++++++++ tests/utils/httpTimeout.test.js | 20 ++++++++++++++++++++ 7 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 src/utils/httpTimeout.js create mode 100644 tests/utils/httpTimeout.test.js diff --git a/.env.example b/.env.example index 0599ae1..bdedc57 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,3 @@ STAGING_TOKEN= PROD_TOKEN= +APIDRIFT_HTTP_TIMEOUT_MS=10000 diff --git a/README.md b/README.md index d95f947..524409c 100644 --- a/README.md +++ b/README.md @@ -129,10 +129,12 @@ After `init`, create a `.env` file (or set env vars) so `${STAGING_TOKEN}` / `${ ```bash STAGING_TOKEN=your_token_here PROD_TOKEN=your_token_here +APIDRIFT_HTTP_TIMEOUT_MS=10000 ``` - Add `.env` to `.gitignore`. - If your `Authorization` header resolves empty (e.g. token missing), apidrift prints a warning before making requests. +- Set `APIDRIFT_HTTP_TIMEOUT_MS` to a positive integer to override the default 10 second HTTP timeout. --- diff --git a/src/core/fetcher.js b/src/core/fetcher.js index 4997523..a56e44f 100644 --- a/src/core/fetcher.js +++ b/src/core/fetcher.js @@ -1,5 +1,6 @@ import axios from "axios"; import { maskSensitiveData } from "./masker.js"; +import { getHttpTimeoutMs } from "../utils/httpTimeout.js"; const RETRY_DEFAULTS = { retries: 3, @@ -29,7 +30,7 @@ async function fetchWithRetry( config = RETRY_DEFAULTS, ) { try { - return await axios({ ...options, url, timeout: 10000 }); + return await axios({ ...options, url, timeout: getHttpTimeoutMs() }); } catch (err) { if (attempt < config.retries && isRetryable(err)) { const delay = Math.min( diff --git a/src/discovery/graphql.js b/src/discovery/graphql.js index 5c5b2d1..082bba0 100644 --- a/src/discovery/graphql.js +++ b/src/discovery/graphql.js @@ -1,4 +1,5 @@ import axios from "axios"; +import { getHttpTimeoutMs } from "../utils/httpTimeout.js"; const INTROSPECTION_QUERY = { query: `{ __schema { queryType { fields { name } } mutationType { fields { name } } } }`, @@ -10,7 +11,7 @@ export async function discoverGraphQL(baseUrl, headers = {}) { url: baseUrl, headers: { "Content-Type": "application/json", ...headers }, data: INTROSPECTION_QUERY, - timeout: 10000, + timeout: getHttpTimeoutMs(), }); const schema = resp.data?.data?.__schema; diff --git a/src/discovery/openapi.js b/src/discovery/openapi.js index 3b8920c..acd6169 100644 --- a/src/discovery/openapi.js +++ b/src/discovery/openapi.js @@ -1,4 +1,5 @@ import axios from "axios"; +import { getHttpTimeoutMs } from "../utils/httpTimeout.js"; export async function discoverOpenAPI( specUrl, @@ -9,7 +10,7 @@ export async function discoverOpenAPI( method: "GET", url: specUrl, headers, - timeout: 10000, + timeout: getHttpTimeoutMs(), }); const spec = resp.data; diff --git a/src/utils/httpTimeout.js b/src/utils/httpTimeout.js new file mode 100644 index 0000000..c95d280 --- /dev/null +++ b/src/utils/httpTimeout.js @@ -0,0 +1,18 @@ +const DEFAULT_HTTP_TIMEOUT_MS = 10000; + +export function getHttpTimeoutMs(env = process.env) { + const rawTimeout = env.APIDRIFT_HTTP_TIMEOUT_MS; + + if (rawTimeout === undefined || rawTimeout === "") { + return DEFAULT_HTTP_TIMEOUT_MS; + } + + const timeout = Number(rawTimeout); + if (!Number.isInteger(timeout) || timeout <= 0) { + throw new Error( + "APIDRIFT_HTTP_TIMEOUT_MS must be a positive integer number of milliseconds", + ); + } + + return timeout; +} diff --git a/tests/utils/httpTimeout.test.js b/tests/utils/httpTimeout.test.js new file mode 100644 index 0000000..070d2ff --- /dev/null +++ b/tests/utils/httpTimeout.test.js @@ -0,0 +1,20 @@ +import { getHttpTimeoutMs } from "../../src/utils/httpTimeout.js"; + +describe("getHttpTimeoutMs", () => { + test("uses the default timeout when env var is unset", () => { + expect(getHttpTimeoutMs({})).toBe(10000); + }); + + test("reads a positive integer timeout from the environment", () => { + expect(getHttpTimeoutMs({ APIDRIFT_HTTP_TIMEOUT_MS: "2500" })).toBe(2500); + }); + + test.each(["0", "-1", "1.5", "abc"])( + "rejects invalid timeout value %s", + (value) => { + expect(() => + getHttpTimeoutMs({ APIDRIFT_HTTP_TIMEOUT_MS: value }), + ).toThrow("APIDRIFT_HTTP_TIMEOUT_MS must be a positive integer"); + }, + ); +});