Skip to main content
Glama
base-client.ts4.16 kB
import axios, { AxiosInstance, AxiosError } from 'axios'; import { PlaneInstanceConfig } from './types/config.js'; export type QueryParams = Record<string, string | number | boolean | Array<string | number> | null | undefined>; interface PlaneErrorResponse { message: string; [key: string]: any; } export class BaseApiClient { protected client: AxiosInstance; protected _instance: PlaneInstanceConfig; public readonly baseUrl: string; constructor(instance: PlaneInstanceConfig) { this._instance = instance; this.baseUrl = instance.baseUrl; // Keep the full baseUrl including /api/v1 since it's part of the base URL const baseURL = this.baseUrl.endsWith('/') ? this.baseUrl.slice(0, -1) // Remove trailing slash if present : this.baseUrl; this.client = axios.create({ baseURL, headers: { 'X-API-Key': instance.apiKey, 'Content-Type': 'application/json', 'Accept': 'application/json' } }); // Add response interceptor for better error handling this.client.interceptors.response.use( response => response, error => { if (axios.isAxiosError(error)) { const axiosError = error as AxiosError<PlaneErrorResponse>; if (axiosError.response?.status === 403) { throw new Error(`API Error (403): Authentication failed. Please check your API key.`); } const errorMessage = axiosError.response?.data?.message || axiosError.message; const errorCode = axiosError.response?.status; throw new Error(`API Error (${errorCode}): ${errorMessage}`); } throw error; } ); } get instance(): PlaneInstanceConfig { return this._instance; } protected handleError(error: AxiosError<PlaneErrorResponse>): never { if (error.response?.status === 403) { throw new Error(`API Error: Authentication failed. Please check your API key.`); } if (error.response?.data?.message) { throw new Error(`API Error: ${error.response.data.message}`); } else if (error.response?.status) { throw new Error(`HTTP Error ${error.response.status}: ${error.message}`); } else { throw new Error(`Network Error: ${error.message}`); } } protected async get<T>(endpoint: string, params?: QueryParams): Promise<T> { try { const response = await this.client.get<T>(endpoint, { params }); return response.data; } catch (error) { this.handleError(error as AxiosError<PlaneErrorResponse>); } } protected async post<T, D = Record<string, unknown>>(endpoint: string, data: D): Promise<T> { try { const response = await this.client.post<T>(endpoint, data); return response.data; } catch (error) { this.handleError(error as AxiosError<PlaneErrorResponse>); } } protected async put<T, D = Record<string, unknown>>(endpoint: string, data: D): Promise<T> { try { const response = await this.client.put<T>(endpoint, data); return response.data; } catch (error) { this.handleError(error as AxiosError<PlaneErrorResponse>); } } protected async delete<T>(endpoint: string): Promise<T> { try { const response = await this.client.delete<T>(endpoint); return response.data; } catch (error) { this.handleError(error as AxiosError<PlaneErrorResponse>); } } protected async patch<T, D = Record<string, unknown>>(endpoint: string, data: D): Promise<T> { try { const response = await this.client.patch<T>(endpoint, data); return response.data; } catch (error) { this.handleError(error as AxiosError<PlaneErrorResponse>); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/deus-h/claudeus-plane-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server