feat(utils): add generic buildQueryString utility
- Add type-safe buildQueryString function to /utils - Support primitives, arrays, and optional values - Proper URL encoding for special characters - Add comprehensive tests (25 test cases, all passing) - Update Google Fonts API client to use shared utility - Update Fontshare API client to use shared utility - Export utility from /utils/index.ts Benefits: - DRY - Single source of truth for query string logic - Type-safe - Proper TypeScript support with QueryParams type - Tested - Comprehensive test coverage - Maintainable - One place to fix bugs
This commit is contained in:
@@ -12,11 +12,13 @@ import type {
|
||||
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 {
|
||||
export interface FontshareParams extends QueryParams {
|
||||
/**
|
||||
* Filter by categories (e.g., ["Sans", "Serif", "Display"])
|
||||
*/
|
||||
@@ -47,36 +49,6 @@ export interface FontshareResponse extends FontshareApiModel {
|
||||
// Response structure matches FontshareApiModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Build query string from parameters
|
||||
*/
|
||||
function buildQueryString(params: FontshareParams): string {
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
if (params.categories?.length) {
|
||||
searchParams.append('categories', params.categories.join(','));
|
||||
}
|
||||
|
||||
if (params.tags?.length) {
|
||||
searchParams.append('tags', params.tags.join(','));
|
||||
}
|
||||
|
||||
if (params.page) {
|
||||
searchParams.append('page', String(params.page));
|
||||
}
|
||||
|
||||
if (params.limit) {
|
||||
searchParams.append('limit', String(params.limit));
|
||||
}
|
||||
|
||||
if (params.search) {
|
||||
searchParams.append('search', params.search);
|
||||
}
|
||||
|
||||
const queryString = searchParams.toString();
|
||||
return queryString ? `?${queryString}` : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch fonts from Fontshare API
|
||||
*
|
||||
@@ -8,11 +8,13 @@
|
||||
*/
|
||||
|
||||
import { api } from '$shared/api/api';
|
||||
import { buildQueryString } from '$shared/utils';
|
||||
import type { QueryParams } from '$shared/utils';
|
||||
|
||||
/**
|
||||
* Google Fonts API parameters
|
||||
*/
|
||||
export interface GoogleFontsParams {
|
||||
export interface GoogleFontsParams extends QueryParams {
|
||||
/**
|
||||
* Google Fonts API key (optional for public endpoints)
|
||||
*/
|
||||
@@ -66,40 +68,6 @@ export interface GoogleFontItem {
|
||||
*/
|
||||
const GOOGLE_FONTS_API_URL = 'https://fonts.googleapis.com/v2/fonts' as const;
|
||||
|
||||
/**
|
||||
* Build query string from parameters
|
||||
*/
|
||||
function buildQueryString(params: GoogleFontsParams): string {
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
if (params.key) {
|
||||
searchParams.append('key', params.key);
|
||||
}
|
||||
|
||||
if (params.family) {
|
||||
searchParams.append('family', params.family);
|
||||
}
|
||||
|
||||
if (params.category) {
|
||||
searchParams.append('category', params.category);
|
||||
}
|
||||
|
||||
if (params.subset) {
|
||||
searchParams.append('subset', params.subset);
|
||||
}
|
||||
|
||||
if (params.sort) {
|
||||
searchParams.append('sort', params.sort);
|
||||
}
|
||||
|
||||
if (params.capability) {
|
||||
searchParams.append('capability', params.capability);
|
||||
}
|
||||
|
||||
const queryString = searchParams.toString();
|
||||
return queryString ? `?${queryString}` : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch fonts from Google Fonts API
|
||||
*
|
||||
@@ -7,33 +7,33 @@
|
||||
export {
|
||||
fetchGoogleFontFamily,
|
||||
fetchGoogleFonts,
|
||||
} from './googleFonts';
|
||||
} from './google/googleFonts';
|
||||
export type {
|
||||
GoogleFontItem,
|
||||
GoogleFontsParams,
|
||||
GoogleFontsResponse,
|
||||
} from './googleFonts';
|
||||
} from './google/googleFonts';
|
||||
|
||||
export {
|
||||
fetchAllFontshareFonts,
|
||||
fetchFontshareFontBySlug,
|
||||
fetchFontshareFonts,
|
||||
} from './fontshare';
|
||||
} from './fontshare/fontshare';
|
||||
export type {
|
||||
FontshareParams,
|
||||
FontshareResponse,
|
||||
} from './fontshare';
|
||||
} from './fontshare/fontshare';
|
||||
|
||||
export {
|
||||
normalizeFontshareFont,
|
||||
normalizeFontshareFonts,
|
||||
normalizeGoogleFont,
|
||||
normalizeGoogleFonts,
|
||||
} from './normalize';
|
||||
} from './normalize/normalize';
|
||||
export type {
|
||||
FontFeatures,
|
||||
FontMetadata,
|
||||
FontStyleUrls,
|
||||
UnifiedFont,
|
||||
UnifiedFontVariant,
|
||||
} from './normalize';
|
||||
} from './normalize/normalize';
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import type { FontshareFont } from '$entities/Font';
|
||||
import type { GoogleFontItem } from '$entities/Font/api/googleFonts';
|
||||
import type { UnifiedFont } from '$entities/Font/api/normalize';
|
||||
import {
|
||||
normalizeFontshareFont,
|
||||
normalizeFontshareFonts,
|
||||
normalizeGoogleFont,
|
||||
normalizeGoogleFonts,
|
||||
} from '$entities/Font/api/normalize';
|
||||
import {
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
} from 'vitest';
|
||||
import type { GoogleFontItem } from '../google/googleFonts';
|
||||
import type { UnifiedFont } from './normalize';
|
||||
import {
|
||||
normalizeFontshareFont,
|
||||
normalizeFontshareFonts,
|
||||
normalizeGoogleFont,
|
||||
normalizeGoogleFonts,
|
||||
} from './normalize';
|
||||
|
||||
describe('Font Normalization', () => {
|
||||
describe('normalizeGoogleFont', () => {
|
||||
@@ -8,10 +8,7 @@
|
||||
*/
|
||||
|
||||
import type { UnifiedFont } from '$entities/Font/api/normalize';
|
||||
import {
|
||||
type CollectionCacheManager,
|
||||
createCollectionCache,
|
||||
} from '$shared/fetch/collectionCache';
|
||||
import { createCollectionCache } from '$shared/fetch/collectionCache';
|
||||
import type {
|
||||
Readable,
|
||||
Writable,
|
||||
|
||||
Reference in New Issue
Block a user