| |
| |
| |
|
|
| import axios from 'axios';
|
| import type { FilterParams, FilterOptions, DataResponse, SummaryStats, ChainMetadata } from '../types/protein';
|
|
|
|
|
| const API_BASE_URL = import.meta.env.VITE_PROTEIN_API_BASE || '/api';
|
|
|
| const api = axios.create({
|
| baseURL: API_BASE_URL,
|
| headers: {
|
| 'Content-Type': 'application/json',
|
| },
|
| });
|
|
|
|
|
| api.interceptors.response.use(
|
| (response) => response,
|
| async (error) => {
|
| const url = error.config?.url || 'unknown';
|
| const method = error.config?.method?.toUpperCase() || 'REQUEST';
|
| const status = error.response?.status || 'NO_RESPONSE';
|
| const statusText = error.response?.statusText || 'Connection failed';
|
|
|
|
|
| let responseBody = '';
|
| if (error.response?.data) {
|
| if (typeof error.response.data === 'string') {
|
| responseBody = error.response.data;
|
| } else {
|
| responseBody = JSON.stringify(error.response.data);
|
| }
|
| }
|
|
|
| const diagnosticMessage = `API Error: ${method} ${url} → ${status} ${statusText}${responseBody ? '\nResponse: ' + responseBody : ''}`;
|
| console.error(diagnosticMessage);
|
|
|
|
|
| error.message = diagnosticMessage;
|
| return Promise.reject(error);
|
| }
|
| );
|
|
|
| export const proteinApi = {
|
| |
| |
|
|
| async getFilters(): Promise<FilterOptions> {
|
| const response = await api.get<FilterOptions>('/protein/filters');
|
| return response.data;
|
| },
|
|
|
| |
| |
|
|
| async getData(filters: FilterParams): Promise<DataResponse> {
|
| const response = await api.post<DataResponse>('/protein/data', filters);
|
| return response.data;
|
| },
|
|
|
| |
| |
|
|
| async getSummary(params?: Partial<FilterParams>): Promise<SummaryStats> {
|
| const response = await api.get<SummaryStats>('/protein/summary', { params });
|
| return response.data;
|
| },
|
|
|
| |
| |
| |
|
|
| async resolveChain(
|
| pdb_id: string,
|
| auth_asym_id: string,
|
| options?: { use_cache?: boolean; signal?: AbortSignal }
|
| ): Promise<ChainMetadata> {
|
| const { use_cache = true, signal } = options || {};
|
| try {
|
| const response = await api.get<ChainMetadata>('/protein/chain/resolve', {
|
| params: { pdb_id, auth_asym_id, use_cache },
|
| signal
|
| });
|
| return response.data;
|
| } catch (error: any) {
|
|
|
| if (error.response?.status === 404) {
|
| const notFoundError: any = new Error('Chain not found');
|
| notFoundError.code = 'NOT_FOUND';
|
| notFoundError.status = 404;
|
| notFoundError.detail = error.response?.data?.detail || 'Chain not found in PDB';
|
| throw notFoundError;
|
| }
|
| throw error;
|
| }
|
| },
|
|
|
| |
| |
|
|
| async batchResolveChains(chains: Array<{ pdb_id: string; auth_asym_id: string }>, use_cache: boolean = true): Promise<Record<string, ChainMetadata>> {
|
| const response = await api.post<Record<string, ChainMetadata>>('/protein/chain/batch-resolve', chains, {
|
| params: { use_cache }
|
| });
|
| return response.data;
|
| },
|
|
|
| |
| |
|
|
| async getChainFunctions(pdb_id: string, auth_asym_id: string): Promise<string[]> {
|
| const response = await api.get<{ functions: string[] }>('/protein/chain/functions', {
|
| params: { pdb_id, auth_asym_id },
|
| });
|
| return response.data.functions;
|
| },
|
| };
|
|
|