UNPKG

@clickup/rest-client

Version:

A syntax sugar tool around Node fetch() API, tailored to work with TypeScript and response validators

90 lines (81 loc) 2.62 kB
import RestRateLimitError from "../errors/RestRateLimitError"; import RestResponseError from "../errors/RestResponseError"; import RestRetriableError from "../errors/RestRetriableError"; import RestTokenInvalidError from "../errors/RestTokenInvalidError"; import type RestOptions from "../RestOptions"; import type RestResponse from "../RestResponse"; const STATUS_TOO_MANY_REQUESTS = 429; /** * The general idea is that we turn all logical errors into exceptions and then * deal with exceptions only. I.e. throwing an exception becomes an internal API * convention for errors. This is because fetch() throws its own exceptions, and * also there may be some exceptions during validation of the response, or * inside a middleware etc. */ export default function throwIfErrorResponse( options: RestOptions, res: RestResponse, ) { const isSuccessResponse = options.isSuccessResponse(res); if (isSuccessResponse === "SUCCESS") { return; } const rateLimitDelayMs = options.isRateLimitError(res); switch (rateLimitDelayMs) { case "RATE_LIMIT": throw new RestRateLimitError( `isRateLimitError() returned ${rateLimitDelayMs}`, 0, res, ); case "BEST_EFFORT": if (res.status === STATUS_TOO_MANY_REQUESTS) { const retryAfterHeader = res.headers.get("Retry-After") || "0"; throw new RestRateLimitError( `Rate limited by HTTP status ${STATUS_TOO_MANY_REQUESTS}`, 1000 * parseInt(retryAfterHeader) || 0, res, ); } break; case "SOMETHING_ELSE": break; default: throw new RestRateLimitError( `isRateLimitError() returned retry delay ${rateLimitDelayMs} ms`, rateLimitDelayMs, res, ); } const isTokenInvalidError = options.isTokenInvalidError(res); if (isTokenInvalidError) { throw new RestTokenInvalidError("Invalid app token", res); } const retryDelayMs = options.isRetriableError(res, null); switch (retryDelayMs) { case "RETRY": throw new RestRetriableError( `isRetriableError() returned ${retryDelayMs}`, 0, res, ); case "BEST_EFFORT": case "NEVER_RETRY": break; default: throw new RestRetriableError( `"isRetriableError() returned retry delay ${retryDelayMs} ms`, retryDelayMs, res, ); } if (isSuccessResponse === "THROW") { throw new RestResponseError( `isSuccessResponse() returned ${isSuccessResponse}`, res, ); } if (res.status >= 300) { throw new RestResponseError("", res); } }