/** * Fontshare API client * * Handles API requests to Fontshare API for fetching font metadata. * Provides error handling, pagination support, and type-safe responses. * * @see https://fontshare.com */ import type { FontshareApiModel, FontshareFont, } from '$entities/Font'; import { api } from '$shared/api/api'; import { buildQueryString } from '$shared/utils'; import type { QueryParams } from '$shared/utils'; /** * Fontshare API parameters */ export interface FontshareParams extends QueryParams { /** * Filter by categories (e.g., ["Sans", "Serif", "Display"]) */ categories?: string[]; /** * Filter by tags (e.g., ["Magazines", "Branding", "Logos"]) */ tags?: string[]; /** * Page number for pagination (1-indexed) */ page?: number; /** * Number of items per page */ limit?: number; /** * Search query to filter fonts */ search?: string; } /** * Fontshare API response wrapper * Extends collection model with additional metadata */ export interface FontshareResponse extends FontshareApiModel { // Response structure matches FontshareApiModel } /** * Fetch fonts from Fontshare API * * @param params - Query parameters for filtering fonts * @returns Promise resolving to Fontshare API response * @throws ApiError when request fails * * @example * ```ts * // Fetch all Sans category fonts * const response = await fetchFontshareFonts({ * categories: ['Sans'], * limit: 50 * }); * * // Fetch fonts with specific tags * const response = await fetchFontshareFonts({ * tags: ['Branding', 'Logos'] * }); * * // Search fonts * const response = await fetchFontshareFonts({ * search: 'Satoshi' * }); * ``` */ export async function fetchFontshareFonts( params: FontshareParams = {}, ): Promise { const queryString = buildQueryString(params); const url = `https://api.fontshare.com/v2${queryString}`; try { const response = await api.get(url); return response.data; } catch (error) { // Re-throw ApiError with context if (error instanceof Error) { throw error; } throw new Error(`Failed to fetch Fontshare fonts: ${String(error)}`); } } /** * Fetch font by slug * Convenience function for fetching a single font * * @param slug - Font slug (e.g., "satoshi", "general-sans") * @returns Promise resolving to Fontshare font item * * @example * ```ts * const satoshi = await fetchFontshareFontBySlug('satoshi'); * ``` */ export async function fetchFontshareFontBySlug( slug: string, ): Promise { const response = await fetchFontshareFonts(); return response.items.find(font => font.slug === slug); } /** * Fetch all fonts from Fontshare * Convenience function for fetching all available fonts * Uses pagination to get all items * * @returns Promise resolving to all Fontshare fonts * * @example * ```ts * const allFonts = await fetchAllFontshareFonts(); * console.log(`Found ${allFonts.items.length} fonts`); * ``` */ export async function fetchAllFontshareFonts( params: FontshareParams = {}, ): Promise { const allFonts: FontshareFont[] = []; let page = 1; const limit = 100; // Max items per page while (true) { const response = await fetchFontshareFonts({ ...params, page, limit, }); allFonts.push(...response.items); // Check if we've fetched all items if (response.items.length < limit) { break; } page++; } // Return first response with all items combined const firstResponse = await fetchFontshareFonts({ ...params, page: 1, limit }); return { ...firstResponse, items: allFonts, }; }