* Make an HTTP request to Paystack API * @param method - HTTP method (GET, POST, PUT, DELETE, etc.) * @param endpoint - API endpoint path * @param data - Request body for POST/PUT/PATCH or query params for GET
(method: string, endpoint: string, data?: any)
| 34 | */ |
| 35 | |
| 36 | async makeRequest<T>(method: string, endpoint: string, data?: any): Promise<PaystackResponse<T>> { |
| 37 | const url = `${this.baseUrl}${endpoint}`; |
| 38 | |
| 39 | const headers: Record<string, string> = { |
| 40 | Authorization: `Bearer ${this.secretKey}`, |
| 41 | 'User-Agent': this.userAgent, |
| 42 | Accept: 'application/json', |
| 43 | }; |
| 44 | |
| 45 | const options: RequestInit = { |
| 46 | method: method.toUpperCase(), |
| 47 | }; |
| 48 | |
| 49 | // Add Content-Type and body for requests with data |
| 50 | if (data && ['POST', 'PUT', 'DELETE', 'PATCH'].includes(method.toUpperCase())) { |
| 51 | headers['Content-Type'] = 'application/json'; |
| 52 | options.body = JSON.stringify(data); |
| 53 | } |
| 54 | options.headers = headers; |
| 55 | |
| 56 | try { |
| 57 | const response = await fetch(url, options); |
| 58 | |
| 59 | // Parse response |
| 60 | const responseText = await response.text(); |
| 61 | let responseData: PaystackResponse<T> | PaystackError; |
| 62 | |
| 63 | try { |
| 64 | responseData = JSON.parse(responseText); |
| 65 | } catch { |
| 66 | // Handle non-JSON responses gracefully (e.g., HTML error pages from API gateways) |
| 67 | const responseSnippet = |
| 68 | responseText.length > 200 ? responseText.substring(0, 200) + '...' : responseText; |
| 69 | const errorMessage = `Received non-JSON response from server (HTTP ${response.status}): ${responseSnippet}`; |
| 70 | const nonJsonError = new Error(errorMessage); |
| 71 | (nonJsonError as any).statusCode = response.status; |
| 72 | (nonJsonError as any).responseText = responseText; |
| 73 | throw nonJsonError; |
| 74 | } |
| 75 | return responseData as PaystackResponse<T>; |
| 76 | } catch (error) { |
| 77 | if (error !== null && (error as any).name === 'NetworkError') { |
| 78 | const timeoutError = new Error(`Request timeout after ${this.timeout} ms`); |
| 79 | (timeoutError as any).statusCode = 408; |
| 80 | throw timeoutError; |
| 81 | } |
| 82 | throw error; |
| 83 | } |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | /** |
no test coverage detected