transformResponse method

  1. @override
Future transformResponse(
  1. RequestOptions options,
  2. ResponseBody responseBody
)
override

transformResponse allows changes to the response data before it is passed to ResponseInterceptor.

Note: As an agreement, you must return the responseBody when the Options.responseType is ResponseType.stream.

Implementation

@override
Future<dynamic> transformResponse(
  RequestOptions options,
  ResponseBody responseBody,
) async {
  final responseType = options.responseType;
  // Do not handled the body for streams.
  if (responseType == ResponseType.stream) {
    return responseBody;
  }

  final int totalLength;
  if (options.onReceiveProgress != null) {
    totalLength = int.parse(
      responseBody.headers[Headers.contentLengthHeader]?.first ?? '-1',
    );
  } else {
    totalLength = 0;
  }

  final streamCompleter = Completer<void>();
  int finalLength = 0;
  // Keep references to the data chunks and concatenate them later.
  final chunks = <Uint8List>[];
  final subscription = responseBody.stream.listen(
    (Uint8List chunk) {
      finalLength += chunk.length;
      chunks.add(chunk);
      options.onReceiveProgress?.call(finalLength, totalLength);
    },
    onError: (Object error, StackTrace stackTrace) {
      streamCompleter.completeError(error, stackTrace);
    },
    onDone: () {
      streamCompleter.complete();
    },
    cancelOnError: true,
  );
  options.cancelToken?.whenCancel.then((_) {
    return subscription.cancel();
  });
  await streamCompleter.future;

  // Copy all chunks into the final bytes.
  final responseBytes = Uint8List(finalLength);
  int chunkOffset = 0;
  for (final chunk in chunks) {
    responseBytes.setAll(chunkOffset, chunk);
    chunkOffset += chunk.length;
  }

  // Return the finalized bytes if the response type is bytes.
  if (responseType == ResponseType.bytes) {
    return responseBytes;
  }

  final isJsonContent = Transformer.isJsonMimeType(
    responseBody.headers[Headers.contentTypeHeader]?.first,
  );
  final String? response;
  if (options.responseDecoder != null) {
    final decodeResponse = options.responseDecoder!(
      responseBytes,
      options,
      responseBody..stream = Stream.empty(),
    );

    if (decodeResponse is Future) {
      response = await decodeResponse;
    } else {
      response = decodeResponse;
    }
  } else if (!isJsonContent || responseBytes.isNotEmpty) {
    response = utf8.decode(responseBytes, allowMalformed: true);
  } else {
    response = null;
  }

  if (response != null &&
      response.isNotEmpty &&
      responseType == ResponseType.json &&
      isJsonContent) {
    return jsonDecodeCallback(response);
  }
  return response;
}