# Proxy API Integration - Changes & Fixes ## Issue Fixed **Error**: `Query data cannot be undefined. Please make sure to return a value other than undefined from your query function. Affected query key: ["unifiedFonts",{}]` **Root Cause**: 1. Missing `gcTime` parameter in TanStack Query configuration 2. No validation of proxy API response structure 3. No error handling for when proxy API returns invalid/missing data ## Changes Made ### 1. Fixed TanStack Query Configuration (`baseFontStore.svelte.ts`) **Added `gcTime` parameter** to properly manage garbage collection of cached data: ```typescript private getOptions(params = this.params): QueryObserverOptions { return { queryKey: this.getQueryKey(params), queryFn: () => this.fetchFn(params), staleTime: 5 * 60 * 1000, // 5 minutes gcTime: 10 * 60 * 1000, // 10 minutes (NEW) }; } ``` **Why this matters**: - Without `gcTime`, TanStack Query uses default (5 minutes) - This can cause cached data to persist longer than intended - May lead to stale data being displayed ### 2. Added Response Validation (`unifiedFontStore.svelte.ts`) **Added comprehensive validation** in `fetchFn` method: ```typescript protected async fetchFn(params: ProxyFontsParams): Promise { const response = await fetchProxyFonts(params); // Validate response structure if (!response) { console.error('[UnifiedFontStore] fetchProxyFonts returned undefined', { params }); throw new Error('Proxy API returned undefined response'); } if (!response.fonts) { console.error('[UnifiedFontStore] response.fonts is undefined', { response }); throw new Error('Proxy API response missing fonts array'); } if (!Array.isArray(response.fonts)) { console.error('[UnifiedFontStore] response.fonts is not an array', { fonts: response.fonts }); throw new Error('Proxy API fonts is not an array'); } // Store pagination metadata separately for derived values this.#paginationMetadata = { total: response.total ?? 0, limit: response.limit ?? this.params.limit ?? 50, offset: response.offset ?? this.params.offset ?? 0, }; return response.fonts; } ``` **Benefits**: - Early error detection when proxy API returns invalid data - Detailed logging for debugging - Prevents undefined data from being cached ### 3. Added Fallback to Fontshare API (`proxyFonts.ts`) **New feature**: Automatic fallback to Fontshare API when proxy fails ```typescript /** * Whether to use proxy API (true) or fallback (false) * * Set to true when your proxy API is ready: * const USE_PROXY_API = true; * * Set to false to use Fontshare API as fallback during development: * const USE_PROXY_API = false; * * The app will automatically fall back to Fontshare API if proxy fails. */ const USE_PROXY_API = true; ``` **Fallback Logic**: ```typescript export async function fetchProxyFonts( params: ProxyFontsParams = {}, ): Promise { // Try proxy API first if enabled if (USE_PROXY_API) { try { const queryString = buildQueryString(params); const url = `${PROXY_API_URL}${queryString}`; console.log('[fetchProxyFonts] Fetching from proxy API', { params, url }); const response = await api.get(url); // Validate response has fonts array if (!response.data || !Array.isArray(response.data.fonts)) { console.error('[fetchProxyFonts] Invalid response from proxy API', response.data); throw new Error('Proxy API returned invalid response'); } console.log('[fetchProxyFonts] Proxy API success', { count: response.data.fonts.length, }); return response.data; } catch (error) { console.warn('[fetchProxyFonts] Proxy API failed, using fallback', error); // Check if it's a network error or proxy not available const isNetworkError = error instanceof Error && (error.message.includes('Failed to fetch') || error.message.includes('Network') || error.message.includes('404') || error.message.includes('500')); if (isNetworkError) { // Fall back to Fontshare API console.log('[fetchProxyFonts] Using Fontshare API as fallback'); return await fetchFontshareFallback(params); } // Re-throw other errors if (error instanceof Error) { throw error; } throw new Error(`Failed to fetch fonts from proxy API: ${String(error)}`); } } // Use Fontshare API directly console.log('[fetchProxyFonts] Using Fontshare API (proxy disabled)'); return await fetchFontshareFallback(params); } ``` **Fallback Function**: ```typescript /** * Fallback to Fontshare API when proxy is unavailable * * Maps proxy API params to Fontshare API params and normalizes response */ async function fetchFontshareFallback( params: ProxyFontsParams, ): Promise { // Import dynamically to avoid circular dependency const { fetchFontshareFonts } = await import('../fontshare/fontshare'); const { normalizeFontshareFonts } = await import('../../lib/normalize/normalize'); // Map proxy params to Fontshare params const fontshareParams = { q: params.q, categories: params.category ? [params.category] : undefined, page: params.offset ? Math.floor(params.offset / (params.limit || 50)) + 1 : undefined, limit: params.limit, }; const response = await fetchFontshareFonts(fontshareParams); const normalizedFonts = normalizeFontshareFonts(response.fonts); return { fonts: normalizedFonts, total: response.count_total, limit: params.limit || response.count, offset: params.offset || 0, }; } ``` **Benefits**: - App continues working even if proxy API is down - Allows development and testing of proxy API without breaking the app - Automatic detection of network/proxy errors - Console logging for debugging ### 4. Updated `fetchProxyFontById` with validation ```typescript export async function fetchProxyFontById( id: string, ): Promise { const response = await fetchProxyFonts({ limit: 1000, q: id }); if (!response || !response.fonts) { console.error('[fetchProxyFontById] No fonts in response', { response }); return undefined; } return response.fonts.find(font => font.id === id); } ``` ## How to Use ### Option 1: Use Proxy API (Recommended for Production) **File**: `src/entities/Font/api/proxy/proxyFonts.ts` ```typescript const USE_PROXY_API = true; ``` When set to `true`: - Fetches from `https://api.glyphdiff.com/api/v1/fonts` - Automatically falls back to Fontshare API on network errors - Provides detailed console logging for debugging ### Option 2: Use Fontshare API (Development Mode) **File**: `src/entities/Font/api/proxy/proxyFonts.ts` ```typescript const USE_PROXY_API = false; ``` When set to `false`: - Uses Fontshare API directly - Uses existing normalization functions - Maintains full functionality while proxy API is being developed ### Option 3: Let App Auto-Fallback (Default Behavior) With `USE_PROXY_API = true`, the app will: 1. Try to fetch from proxy API 2. If network error (404, 500, network failure), automatically use Fontshare API 3. Log all attempts to console for debugging ## Testing the Proxy API ### Step 1: Verify Proxy API is Running ```bash curl "https://api.glyphdiff.com/api/v1/fonts?limit=1" ``` Expected response: ```json { "fonts": [...], "total": N, "limit": 1, "offset": 0 } ``` ### Step 2: Test Proxy API with Filters ```bash # Test provider filter curl "https://api.glyphdiff.com/api/v1/fonts?provider=fontshare&limit=5" # Test category filter curl "https://api.glyphdiff.com/api/v1/fonts?category=sans-serif&limit=5" # Test search curl "https://api.glyphdiff.com/api/v1/fonts?q=roboto&limit=5" # Test pagination curl "https://api.glyphdiff.com/api/v1/fonts?limit=10&offset=10" # Test sorting curl "https://api.glyphdiff.com/api/v1/fonts?sort=popularity&limit=5" ``` ### Step 3: Check Console Logs Open browser console and look for: - `[fetchProxyFonts] Fetching from proxy API` - Attempting proxy - `[fetchProxyFonts] Proxy API success` - Proxy API worked - `[fetchProxyFonts] Proxy API failed, using fallback` - Falling back to Fontshare - `[fetchProxyFonts] Using Fontshare API as fallback` - Using Fontshare directly - `[fetchProxyFonts] Using Fontshare API (proxy disabled)` - Proxy is disabled ## Troubleshooting ### Problem: "Query data cannot be undefined" **Cause**: Proxy API returned invalid response or didn't return fonts array **Solution**: 1. Check console for error messages 2. Verify proxy API returns correct structure 3. Set `USE_PROXY_API = false` to use Fontshare API as fallback ### Problem: Network Error / CORS Error **Cause**: Proxy API is not accessible or CORS headers missing **Solution**: 1. Set `USE_PROXY_API = false` to bypass proxy temporarily 2. Fix CORS headers on proxy API server 3. Ensure proxy API is accessible from your domain ### Problem: Fonts Not Loading **Cause**: Proxy API returns empty fonts array **Solution**: 1. Check proxy API response in Network tab 2. Verify proxy API has fonts in database 3. Test with simple query: `?limit=5` ### Problem: Pagination Not Working **Cause**: Proxy API `total` or `offset` fields missing or incorrect **Solution**: 1. Verify proxy API returns `total` field 2. Verify proxy API returns `limit` and `offset` fields 3. Test pagination manually with curl ## Proxy API Requirements For the frontend to work correctly, your proxy API MUST return: ```typescript interface ProxyFontsResponse { fonts: UnifiedFont[]; // REQUIRED: Array of fonts total: number; // REQUIRED: Total matching fonts limit: number; // REQUIRED: Current page limit offset: number; // REQUIRED: Current offset } ``` Each `UnifiedFont` must have: ```typescript interface UnifiedFont { id: string; // REQUIRED: Unique identifier name: string; // REQUIRED: Display name provider: 'google' | 'fontshare'; // REQUIRED: Provider category: FontCategory; // REQUIRED: Font category subsets: FontSubset[]; // REQUIRED: Supported subsets variants: string[]; // REQUIRED: Available variants styles: FontStyleUrls; // REQUIRED: Font style URLs metadata: FontMetadata; // REQUIRED: Version, cachedAt, etc. features: FontFeatures; // REQUIRED: Variable font info } ``` ## Files Modified 1. `src/entities/Font/model/store/baseFontStore.svelte.ts` - Added `gcTime` parameter 2. `src/entities/Font/model/store/unifiedFontStore.svelte.ts` - Added response validation in `fetchFn` - Added detailed error logging 3. `src/entities/Font/api/proxy/proxyFonts.ts` - Added `USE_PROXY_API` flag - Added fallback logic to Fontshare API - Added response validation - Added console logging - Updated JSDoc with examples ## Verification All changes pass: - ✅ Type checking (`yarn check`) - ✅ Linting (`yarn lint`) - ✅ No new errors introduced - ✅ Backward compatibility maintained - ✅ Fallback mechanism works ## Next Steps 1. **Test Proxy API**: Use curl or Postman to verify your proxy API works 2. **Set `USE_PROXY_API = true`**: Enable proxy API when ready 3. **Monitor Console Logs**: Check for proxy API success/failure messages 4. **Remove Fallback** (Optional): Once proxy API is stable, remove Fontshare fallback --- **Last Updated**: January 29, 2026