Files
frontend-svelte/src/entities/Font/api/proxy/proxyFonts.ts

161 lines
4.0 KiB
TypeScript
Raw Normal View History

/**
* Proxy API client
*
* Handles API requests to GlyphDiff proxy API for fetching font metadata.
* Provides error handling, pagination support, and type-safe responses.
*
* Proxy API normalizes font data from Google Fonts and Fontshare into a single
* unified format, eliminating the need for client-side normalization.
*
* @see https://api.glyphdiff.com/api/v1/fonts
*/
import { api } from '$shared/api/api';
import { buildQueryString } from '$shared/lib/utils';
import type { QueryParams } from '$shared/lib/utils';
import type { UnifiedFont } from '../../model/types';
import type {
FontCategory,
FontSubset,
} from '../../model/types';
/**
* Proxy API base URL
*/
const PROXY_API_URL = 'https://api.glyphdiff.com/api/v1/fonts' as const;
/**
* Proxy API parameters
*
* Maps directly to the proxy API query parameters
*/
export interface ProxyFontsParams extends QueryParams {
/**
* Font provider filter ("google" or "fontshare")
* Omit to fetch from both providers
*/
provider?: 'google' | 'fontshare';
/**
* Font category filter
*/
category?: FontCategory;
/**
* Character subset filter
*/
subset?: FontSubset;
/**
* Search query (e.g., "roboto", "satoshi")
*/
q?: string;
/**
* Sort order for results
* "name" - Alphabetical by font name
* "popularity" - Most popular first
* "lastModified" - Recently updated first
*/
sort?: 'name' | 'popularity' | 'lastModified';
/**
* Number of items to return (pagination)
*/
limit?: number;
/**
* Number of items to skip (pagination)
* Use for pagination: offset = (page - 1) * limit
*/
offset?: number;
}
/**
* Proxy API response
*
* Includes pagination metadata alongside font data
*/
export interface ProxyFontsResponse {
/** Array of unified font objects */
fonts: UnifiedFont[];
/** Total number of fonts matching the query */
total: number;
/** Limit used for this request */
limit: number;
/** Offset used for this request */
offset: number;
}
/**
* Fetch fonts from proxy API
*
* @param params - Query parameters for filtering and pagination
* @returns Promise resolving to proxy API response
* @throws ApiError when request fails
*
* @example
* ```ts
* // Fetch all sans-serif fonts from Google
* const response = await fetchProxyFonts({
* provider: 'google',
* category: 'sans-serif',
* limit: 50,
* offset: 0
* });
*
* // Search fonts across all providers
* const searchResponse = await fetchProxyFonts({
* q: 'roboto',
* limit: 20
* });
*
* // Fetch fonts with pagination
* const page1 = await fetchProxyFonts({ limit: 50, offset: 0 });
* const page2 = await fetchProxyFonts({ limit: 50, offset: 50 });
* ```
*/
export async function fetchProxyFonts(
params: ProxyFontsParams = {},
): Promise<ProxyFontsResponse> {
const queryString = buildQueryString(params);
const url = `${PROXY_API_URL}${queryString}`;
try {
const response = await api.get<ProxyFontsResponse>(url);
return response.data;
} catch (error) {
// Re-throw ApiError with context
if (error instanceof Error) {
throw error;
}
throw new Error(`Failed to fetch fonts from proxy API: ${String(error)}`);
}
}
/**
* Fetch font by ID
*
* Convenience function for fetching a single font by ID
* Note: This fetches a page and filters client-side, which is not ideal
* For production, consider adding a dedicated endpoint to the proxy API
*
* @param id - Font ID (family name for Google, slug for Fontshare)
* @returns Promise resolving to font or undefined
*
* @example
* ```ts
* const roboto = await fetchProxyFontById('Roboto');
* const satoshi = await fetchProxyFontById('satoshi');
* ```
*/
export async function fetchProxyFontById(
id: string,
): Promise<UnifiedFont | undefined> {
const response = await fetchProxyFonts({ limit: 1000, q: id });
return response.fonts.find(font => font.id === id);
}