fromHttpResponse static method
Implementation
static Future<ApiCallResponse> fromHttpResponse(http.Response response, bool returnBody, bool decodeUtf8) async {
var jsonBody;
Pagination? pagination;
ApiError? error;
try {
final responseBody = decodeUtf8 && returnBody ? const Utf8Decoder().convert(response.bodyBytes) : response.body;
if (returnBody) {
// Large payload (>1MB) → decode in isolate to avoid jank.
// Smaller payloads → sync decode (isolate spawn overhead not worth it).
if (response.bodyBytes.length > 1024 * 1024) {
jsonBody = await compute(json.decode, responseBody);
} else {
jsonBody = json.decode(responseBody);
}
} else {
jsonBody = null;
}
if (jsonBody is Map) {
error =
jsonBody["error"] != null
? ApiError.fromJson(jsonObject: jsonBody["error"])
: (jsonBody["statusCode"] != null ? ApiError.fromJson(jsonObject: jsonBody) : null);
// Pagination: formato standard {meta: {total, lastPage, currentPage, perPage}}
if (jsonBody["meta"] != null) {
pagination = Pagination.fromJson(jsonObject: jsonBody["meta"]);
}
// Pagination: formato HR {total, page, limit, totalPages} a livello root
else if (jsonBody["total"] != null && jsonBody["items"] != null) {
final p = Pagination();
p.total = jsonBody['total'] as int?;
p.currentPage = jsonBody['page'] as int?;
p.perPage = jsonBody['limit'] as int?;
p.lastPage = jsonBody['totalPages'] as int?;
if (p.currentPage != null && p.currentPage! > 1) {
p.prev = p.currentPage! - 1;
}
if (p.currentPage != null && p.lastPage != null && p.currentPage! < p.lastPage!) {
p.next = p.currentPage! + 1;
}
pagination = p;
}
}
} catch (_) {}
// Estrae i dati: se è un Map usa "data" o "items", altrimenti body intero
final extractedBody = jsonBody is Map
? (jsonBody["data"] ?? jsonBody["items"] ?? jsonBody)
: jsonBody;
return ApiCallResponse(
extractedBody,
pagination,
error,
response.headers,
response.statusCode,
response: response,
);
}