/** * Flattens one level of nested objects before serializing to a query string. * Useful when a backend (e.g. Spring Boot Pageable / @ModelAttribute) expects * flat params (page=0&size=10) instead of Axios's default bracket notation * (pageable[page]=0&pageable[size]=10). * * Arrays at any level are repeated: sort=name,asc&sort=id,desc * null/undefined values are omitted. */ export const paramsSerializer = (params: Record): string => { const parts: string[] = []; for (const [key, value] of Object.entries(params)) { if (value === undefined || value === null) continue; if (typeof value === 'object' && !Array.isArray(value)) { for (const [k, v] of Object.entries(value as Record)) { if (v === undefined || v === null) continue; if (Array.isArray(v)) { for (const item of v) parts.push( `${encodeURIComponent(k)}=${encodeURIComponent(String(item))}`, ); } else { parts.push( `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`, ); } } } else if (Array.isArray(value)) { for (const item of value) parts.push( `${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`, ); } else { parts.push( `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`, ); } } return parts.join('&'); };