Overview
The fetchApiSplit function automatically splits array parameters into multiple smaller requests when they exceed specified limits. This is useful for Roblox endpoints that have maximum array size limits (e.g., “max 100 universe IDs per request”).
All split requests are executed in parallel using Promise.all() for optimal performance.
Signature
async function fetchApiSplit<S extends EndpointSchema, T = ExtractResponse<S>>(
endpoint: S,
params: ExtractParams<S>,
max?: Partial<{ [K in keyof ExtractParams<S>]: number }>,
transform?: (response: ExtractResponse<S>) => T,
requestOptions?: RequestOptions
): Promise<T[] | AnyError>
Parameters
The endpoint definition object to make requests to.
Parameters to pass to the endpoint. Array parameters will be split according to the max configuration.
max
Partial<Record<string, number>>
Object specifying the maximum size for each array parameter. Keys are parameter names, values are the maximum items per request.Example: { universeIds: 100 } means split universeIds into chunks of 100.If not provided or empty, makes a single request without splitting.
transform
(response: ExtractResponse<S>) => T
Optional function to transform each response before returning. By default, returns the full response.Useful for extracting just the data field or mapping responses to a different format.
Additional options applied to each request. See fetchApi for available options.
Return value
Returns a Promise that resolves to:
- Success: Array of transformed results (one per batch)
- Error: An
AnyError object if any request fails (short-circuits on first error)
Examples
Basic splitting
import { fetchApiSplit } from 'rozod';
import { getGamesIcons } from 'rozod/lib/endpoints/gamesv1';
// Request 500 universe IDs, split into batches of 100
const results = await fetchApiSplit(
getGamesIcons,
{ universeIds: [1, 2, 3, /* ... 500 IDs total */] },
{ universeIds: 100 }
);
// Results is an array of 5 responses (500 / 100 = 5 batches)
if (!isAnyErrorResponse(results)) {
console.log(`Fetched ${results.length} batches`);
results.forEach((batch, index) => {
console.log(`Batch ${index + 1}:`, batch.data);
});
}
Extract just the data field from each response:
import { fetchApiSplit } from 'rozod';
import { getGamesIcons } from 'rozod/lib/endpoints/gamesv1';
const results = await fetchApiSplit(
getGamesIcons,
{ universeIds: [1, 2, 3, 4, 5] },
{ universeIds: 100 },
(response) => response.data // Extract just the data array
);
// Now results is an array of data arrays
if (!isAnyErrorResponse(results)) {
// results: Array<Array<GameIconData>>
results.forEach((dataArray, index) => {
console.log(`Batch ${index + 1} has ${dataArray.length} icons`);
});
}
Flatten results
Combine all batches into a single array:
import { fetchApiSplit, isAnyErrorResponse } from 'rozod';
import { getUsersUserdetails } from 'rozod/lib/endpoints/usersv1';
const batchedResults = await fetchApiSplit(
getUsersUserdetails,
{ userIds: [1, 2, 3, /* ... 500 user IDs */] },
{ userIds: 100 },
(response) => response.data
);
if (!isAnyErrorResponse(batchedResults)) {
// Flatten all batches into a single array
const allUsers = batchedResults.flat();
console.log(`Fetched ${allUsers.length} total users`);
}
Multiple array parameters
import { fetchApiSplit } from 'rozod';
import { someEndpoint } from 'rozod/lib/endpoints/somev1';
const results = await fetchApiSplit(
someEndpoint,
{
userIds: [1, 2, 3, /* ... 200 IDs */],
groupIds: [10, 20, 30, /* ... 150 IDs */]
},
{
userIds: 50, // Split userIds into chunks of 50
groupIds: 25 // Split groupIds into chunks of 25
}
);
With request options
const results = await fetchApiSplit(
getGamesIcons,
{ universeIds: [1, 2, 3, /* ... */] },
{ universeIds: 100 },
(response) => response.data,
{
retries: 3,
retryDelay: 1000,
throwOnError: true
}
);
Without splitting
// If you don't provide 'max', it makes a single request
const results = await fetchApiSplit(
getGamesIcons,
{ universeIds: [1, 2, 3] }
// No max parameter
);
// results is still an array, but with only one element
if (!isAnyErrorResponse(results)) {
console.log(results.length); // 1
console.log(results[0]); // Single response object
}
Advanced usage
import { fetchApiSplit } from 'rozod';
import { getGamesIcons } from 'rozod/lib/endpoints/gamesv1';
interface GameIcon {
universeId: number;
iconUrl: string;
}
const results = await fetchApiSplit(
getGamesIcons,
{ universeIds: [1, 2, 3, /* ... */] },
{ universeIds: 100 },
(response) => {
// Transform each item in the response
return response.data.map(item => ({
universeId: item.targetId,
iconUrl: item.imageUrl
}));
}
);
// results: Array<Array<GameIcon>>
if (!isAnyErrorResponse(results)) {
const allIcons = results.flat();
console.log('All icons:', allIcons);
}
Error handling
import { fetchApiSplit, isAnyErrorResponse } from 'rozod';
import { getGamesIcons } from 'rozod/lib/endpoints/gamesv1';
const results = await fetchApiSplit(
getGamesIcons,
{ universeIds: [1, 2, 3, /* ... */] },
{ universeIds: 100 }
);
if (isAnyErrorResponse(results)) {
console.error('Request failed:', results.message);
console.error('Error code:', results.code);
} else {
console.log(`Successfully fetched ${results.length} batches`);
// Process results
results.forEach(batch => {
console.log(batch.data);
});
}
With throw on error
try {
const results = await fetchApiSplit(
getGamesIcons,
{ universeIds: [1, 2, 3, /* ... */] },
{ universeIds: 100 },
(response) => response.data,
{ throwOnError: true }
);
// results is guaranteed to be successful here
const allData = results.flat();
console.log('All data:', allData);
} catch (error) {
console.error('Request failed:', (error as Error).message);
}
How it works
- The function examines the
max parameter to determine which array parameters need splitting
- For each specified parameter, it splits the array into chunks of the specified size
- Creates parameter objects for each batch
- Executes all requests in parallel using
Promise.all()
- Applies the optional transform function to each response
- Returns an array of transformed results
- Short-circuits and returns the first error if any request fails
Type safety
The function maintains full type safety:
import { fetchApiSplit } from 'rozod';
import { getGamesIcons } from 'rozod/lib/endpoints/gamesv1';
// Without transform - array of full responses
const fullResults = await fetchApiSplit(
getGamesIcons,
{ universeIds: [1, 2, 3] },
{ universeIds: 100 }
);
if (!isAnyErrorResponse(fullResults)) {
fullResults.forEach(response => {
response.data // ✓ Typed correctly
});
}
// With transform - array of transformed results
const dataResults = await fetchApiSplit(
getGamesIcons,
{ universeIds: [1, 2, 3] },
{ universeIds: 100 },
(response) => response.data
);
if (!isAnyErrorResponse(dataResults)) {
dataResults.forEach(dataArray => {
// dataArray is typed as the data field type
dataArray.forEach(item => {
item.imageUrl // ✓ Typed correctly
});
});
}
All split requests are executed in parallel for optimal performance. The function waits for all requests to complete before returning.
If any single request fails, the entire function returns an error. Consider using individual fetchApi calls with custom error handling if you need more granular control.