diff --git a/sdk/src/lib/api/HttpApi.ts b/sdk/src/lib/api/HttpApi.ts index d1759d6d2..696156715 100644 --- a/sdk/src/lib/api/HttpApi.ts +++ b/sdk/src/lib/api/HttpApi.ts @@ -1,11 +1,48 @@ +import { backoffRetrier, RetryOptions } from "../utils" + /** * Represents an abstract HTTP API. */ export default abstract class HttpApi { #apiUrl: string - constructor(apiUrl: string) { + /** + * Retry options for API requests. + */ + #retryOptions: RetryOptions + + constructor( + apiUrl: string, + retryOptions: RetryOptions = { + retries: 5, + backoffStepMs: 1000, + }, + ) { this.#apiUrl = apiUrl + this.#retryOptions = retryOptions + } + + /** + * Makes an HTTP request with retry logic. + * @param requestFn Function that returns a Promise of the HTTP response. + * @returns The HTTP response. + * @throws Error if the request fails after all retries. + */ + async requestWithRetry( + requestFn: () => Promise, + ): Promise { + return backoffRetrier( + this.#retryOptions.retries, + this.#retryOptions.backoffStepMs, + )(async () => { + const response = await requestFn() + + if (!response.ok) { + throw new Error(`Request failed: ${await response.text()}`) + } + + return response + }) } /** diff --git a/sdk/src/lib/api/TbtcApi.ts b/sdk/src/lib/api/TbtcApi.ts index 931e36601..a1baf46c4 100644 --- a/sdk/src/lib/api/TbtcApi.ts +++ b/sdk/src/lib/api/TbtcApi.ts @@ -38,12 +38,11 @@ export default class TbtcApi extends HttpApi { * otherwise. */ async saveReveal(revealData: SaveRevealRequest): Promise { - const response = await this.postRequest("reveals", revealData) - - if (!response.ok) - throw new Error( - `Reveal not saved properly in the database, response: ${response.status}`, - ) + const response = await this.requestWithRetry(async () => + this.postRequest("reveals", revealData), + ).catch((error) => { + throw new Error(`Failed to save reveal: ${error}`) + }) const { success } = (await response.json()) as { success: boolean } @@ -60,11 +59,11 @@ export default class TbtcApi extends HttpApi { depositStatus: DepositStatus fundingOutpoint: BitcoinTxOutpoint }> { - const response = await this.postRequest("deposits", depositData) - if (!response.ok) - throw new Error( - `Bitcoin deposit creation failed, response: ${response.status}`, - ) + const response = await this.requestWithRetry(async () => + this.postRequest("deposits", depositData), + ).catch((error) => { + throw new Error(`Failed to create deposit: ${error}`) + }) const responseData = (await response.json()) as CreateDepositResponse @@ -83,12 +82,11 @@ export default class TbtcApi extends HttpApi { * @returns All owner deposits, including queued deposits. */ async getDepositsByOwner(depositOwner: ChainIdentifier): Promise { - const response = await this.getRequest( - `deposits/${depositOwner.identifierHex}`, - ) - - if (!response.ok) - throw new Error(`Failed to fetch deposits: ${response.status}`) + const response = await this.requestWithRetry(async () => + this.getRequest(`deposits/${depositOwner.identifierHex}`), + ).catch((error) => { + throw new Error(`Failed to fetch deposits: ${error}`) + }) const responseData = (await response.json()) as Deposit[]