Implement main class & fetch function - including robust error handling.
This commit is contained in:
96
src/clients/client.ts
Normal file
96
src/clients/client.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { version } from "../constants";
|
||||
import { LdbClientV2 } from "./LdbClientV2";
|
||||
import { LocationReferenceClientV2 } from "./LocationReferenceClientV2";
|
||||
import { MiscClientV2 } from "./MiscClientV2";
|
||||
import { PisClientV2 } from "./PisClientV2";
|
||||
import { TrainClientV2 } from "./TrainClientV2";
|
||||
import { UserClientV2 } from "./UserClientV2";
|
||||
|
||||
import { ApiError, NetworkError } from "../errors";
|
||||
|
||||
export class BaseOwlBoardClient {
|
||||
protected baseUrl: string;
|
||||
protected apiKey: string;
|
||||
protected headers: Record<string, string>;
|
||||
|
||||
constructor(baseUrl: string, apiKey: string) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.apiKey = apiKey;
|
||||
this.headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
"User-Agent": `OwlBoardTS/v${version}`,
|
||||
"uuid": this.apiKey,
|
||||
};
|
||||
}
|
||||
|
||||
async makeRequest<T>(method: string, path: string, body?: any): Promise<T> {
|
||||
const url = `${this.baseUrl}${path}`;
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers: this.headers,
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
};
|
||||
|
||||
let attempt = 0;
|
||||
const retries = 3;
|
||||
const delay = 500;
|
||||
const retryableStatusCodes = [408, 500, 502, 503, 504];
|
||||
|
||||
while (attempt < retries) {
|
||||
try {
|
||||
const response = await fetch(url, options);
|
||||
if (!response.ok) {
|
||||
const responseBody = await response.text();
|
||||
const apiError = new ApiError("API Request Failed", response.status, responseBody);
|
||||
if (retryableStatusCodes.includes(response.status)) {
|
||||
attempt++;
|
||||
if (attempt >= retries) { // Max attempts reached
|
||||
throw apiError;
|
||||
}
|
||||
// Wait before retrying
|
||||
await new Promise(res => setTimeout(res, delay));
|
||||
continue; // Retry
|
||||
} else { // Non-retryable status codes
|
||||
throw apiError;
|
||||
}
|
||||
}
|
||||
|
||||
return (await response.json()) as T;
|
||||
} catch (error) {
|
||||
if (error instanceof TypeError) { // Indicates network errors with fetch
|
||||
if (attempt < retries) {
|
||||
attempt ++;
|
||||
await new Promise(res => setTimeout(res, delay));
|
||||
continue;
|
||||
}
|
||||
// Throw network error if max tries reached handling TypeError
|
||||
throw new NetworkError("Network request failed");
|
||||
};
|
||||
|
||||
throw error; // Rethrow any other error
|
||||
};
|
||||
}
|
||||
// This code should never be reached.
|
||||
throw new Error("Unexpected error after multiple retries.")
|
||||
}
|
||||
}
|
||||
|
||||
export class OwlBoardClientV2 extends BaseOwlBoardClient {
|
||||
pis: PisClientV2;
|
||||
train: TrainClientV2;
|
||||
user: UserClientV2;
|
||||
locationReference: LocationReferenceClientV2;
|
||||
misc: MiscClientV2;
|
||||
ldb: LdbClientV2;
|
||||
|
||||
constructor(baseUrl: string, apiKey: string) {
|
||||
super(baseUrl, apiKey);
|
||||
this.pis = new PisClientV2(this);
|
||||
this.train = new TrainClientV2(this);
|
||||
this.user = new UserClientV2(this);
|
||||
this.locationReference = new LocationReferenceClientV2(this);
|
||||
this.misc = new MiscClientV2(this);
|
||||
this.ldb = new LdbClientV2(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user