- Built from scratch: apollo, chargebee, datadog, greenhouse, lever, loom, pandadoc, salesloft, sendgrid, supabase, typeform, webflow, zoho-crm, twilio, reonomy - TSC fixes: brevo, google-console, housecall-pro, meta-ads, rippling, bamboohr, close, fieldedge, freshdesk, helpscout, toast, touchbistro, hubspot, notion, quickbooks, airtable, gusto, intercom, linear, monday, salesforce, shopify, square, wave, xero - Entry points added: close, touchbistro - All 65 active servers compile with 0 TypeScript errors - 4 specialty servers skipped (competitor-research, compliance-grc, n8n-apps, product-analytics)
111 lines
3.3 KiB
TypeScript
111 lines
3.3 KiB
TypeScript
/**
|
|
* Datadog API Client
|
|
* Handles authentication, rate limiting, and API requests
|
|
*/
|
|
|
|
import axios, { AxiosInstance, AxiosError } from 'axios';
|
|
import Bottleneck from 'bottleneck';
|
|
import type { DatadogConfig } from '../types/index.js';
|
|
|
|
export class DatadogClient {
|
|
private client: AxiosInstance;
|
|
private limiter: Bottleneck;
|
|
private apiKey: string;
|
|
private appKey: string;
|
|
|
|
constructor(config: DatadogConfig) {
|
|
this.apiKey = config.apiKey;
|
|
this.appKey = config.appKey;
|
|
|
|
// Initialize rate limiter
|
|
this.limiter = new Bottleneck({
|
|
maxConcurrent: config.rateLimit?.maxConcurrent || 10,
|
|
minTime: config.rateLimit?.minTime || 100,
|
|
});
|
|
|
|
// Initialize axios client
|
|
const site = config.site || 'datadoghq.com';
|
|
this.client = axios.create({
|
|
baseURL: `https://api.${site}/api`,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'DD-API-KEY': this.apiKey,
|
|
'DD-APPLICATION-KEY': this.appKey,
|
|
},
|
|
});
|
|
|
|
// Add response interceptor for error handling
|
|
this.client.interceptors.response.use(
|
|
(response) => response,
|
|
(error: AxiosError) => {
|
|
return Promise.reject(this.handleError(error));
|
|
}
|
|
);
|
|
}
|
|
|
|
private handleError(error: AxiosError): Error {
|
|
if (error.response) {
|
|
const status = error.response.status;
|
|
const data = error.response.data as any;
|
|
|
|
switch (status) {
|
|
case 400:
|
|
return new Error(`Datadog API bad request: ${JSON.stringify(data)}`);
|
|
case 401:
|
|
return new Error('Datadog API authentication failed. Check your API key.');
|
|
case 403:
|
|
return new Error('Datadog API access forbidden. Check your application key permissions.');
|
|
case 404:
|
|
return new Error('Datadog API resource not found.');
|
|
case 429:
|
|
return new Error('Datadog API rate limit exceeded. Please retry later.');
|
|
case 500:
|
|
case 502:
|
|
case 503:
|
|
return new Error('Datadog API server error. Please retry later.');
|
|
default:
|
|
return new Error(`Datadog API error (${status}): ${JSON.stringify(data)}`);
|
|
}
|
|
} else if (error.request) {
|
|
return new Error('Datadog API request failed. No response received.');
|
|
} else {
|
|
return new Error(`Datadog API error: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
async get<T>(path: string, params?: Record<string, any>): Promise<T> {
|
|
return this.limiter.schedule(async () => {
|
|
const response = await this.client.get<T>(path, { params });
|
|
return response.data;
|
|
});
|
|
}
|
|
|
|
async post<T>(path: string, data?: any): Promise<T> {
|
|
return this.limiter.schedule(async () => {
|
|
const response = await this.client.post<T>(path, data);
|
|
return response.data;
|
|
});
|
|
}
|
|
|
|
async put<T>(path: string, data?: any): Promise<T> {
|
|
return this.limiter.schedule(async () => {
|
|
const response = await this.client.put<T>(path, data);
|
|
return response.data;
|
|
});
|
|
}
|
|
|
|
async patch<T>(path: string, data?: any): Promise<T> {
|
|
return this.limiter.schedule(async () => {
|
|
const response = await this.client.patch<T>(path, data);
|
|
return response.data;
|
|
});
|
|
}
|
|
|
|
async delete<T>(path: string): Promise<T> {
|
|
return this.limiter.schedule(async () => {
|
|
const response = await this.client.delete<T>(path);
|
|
return response.data;
|
|
});
|
|
}
|
|
}
|