tskew
Version:
TypeScript interface to Kew Gardens botanical data services
78 lines • 3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Api = void 0;
class Api {
constructor(baseUrl, config = {}) {
this.baseUrl = baseUrl;
this.config = {
timeout: 30000,
retries: 3,
retryDelay: 1000,
...config,
};
}
buildUrl(endpoint, params = {}) {
// Ensure baseUrl ends with / and endpoint starts with /
const baseUrlNormalized = this.baseUrl.endsWith("/")
? this.baseUrl
: this.baseUrl + "/";
const endpointNormalized = endpoint.startsWith("/")
? endpoint.slice(1)
: endpoint;
const url = new URL(endpointNormalized, baseUrlNormalized);
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
url.searchParams.append(key, String(value));
}
});
return url.toString();
}
async makeRequest(url, retryCount = 0) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
try {
const response = await fetch(url, {
method: "GET",
headers: {
"User-Agent": "python-requests/2.31.0",
Accept: "*/*",
"Accept-Encoding": "gzip, deflate",
Connection: "keep-alive",
},
signal: controller.signal,
});
clearTimeout(timeoutId);
// Check if response is ok
if (!response.ok) {
// Match pykew behavior: retry on status code 249 (rate limit)
if (response.status === 249 && retryCount < this.config.retries) {
// Wait 5 seconds like pykew does
await new Promise((resolve) => setTimeout(resolve, 5000));
return this.makeRequest(url, retryCount + 1);
}
const errorText = await response.text();
throw new Error(`HTTP ${response.status}: ${response.statusText}. ${errorText}`);
}
const data = await response.json();
return data;
}
catch (error) {
clearTimeout(timeoutId);
if (error.name === "AbortError") {
throw new Error(`Request timeout after ${this.config.timeout}ms`);
}
// For other errors, retry if configured
if (retryCount < this.config.retries) {
await new Promise((resolve) => setTimeout(resolve, this.config.retryDelay));
return this.makeRequest(url, retryCount + 1);
}
throw error;
}
}
async get(endpoint, params = {}) {
const url = this.buildUrl(endpoint, params);
return this.makeRequest(url);
}
}
exports.Api = Api;
//# sourceMappingURL=api.js.map