uploadFile method

Future<ClientResult> uploadFile({
  1. required String url,
  2. required String filePath,
  3. required String fileField,
  4. Map<String, String>? fields,
  5. Map<String, String>? headers,
  6. Duration? timeout,
  7. ClientType? clientType,
  8. OnProgress? onProgress,
  9. String? cancelKey,
  10. OnSuccess? onSuccess,
  11. OnError? onError,
  12. OnHttpError? onHttpError,
  13. Map<int, OnStatus>? onStatus,
  14. Set<int>? successCodes,
  15. Set<int>? errorCodes,
})

Uploads a file using multipart/form-data.

Returns a ClientResult tuple. Optionally accepts callbacks for convenient response handling.

Implementation

Future<ClientResult> uploadFile({
  required String url,
  required String filePath,
  required String fileField,
  Map<String, String>? fields,
  Map<String, String>? headers,
  Duration? timeout,
  ClientType? clientType,
  OnProgress? onProgress,
  String? cancelKey,
  // Optional callbacks
  OnSuccess? onSuccess,
  OnError? onError,
  OnHttpError? onHttpError,
  Map<int, OnStatus>? onStatus,
  Set<int>? successCodes,
  Set<int>? errorCodes,
}) async {
  final fullUrl = _buildUrl(url);
  final useClient = clientType ?? config.clientType;
  final stopwatch = Stopwatch()..start();

  try {
    if (useClient == ClientType.dio) {
      dio.CancelToken? cancelToken;
      if (cancelKey != null) {
        cancelToken = dio.CancelToken();
        _cancelTokens[cancelKey] = cancelToken;
      }

      final formData = dio.FormData.fromMap({
        ...?fields,
        fileField: await dio.MultipartFile.fromFile(filePath),
      });

      final response = await _dio.post(
        fullUrl,
        data: formData,
        options: dio.Options(
          headers: headers,
          sendTimeout: timeout ?? config.sendTimeout,
        ),
        onSendProgress: onProgress,
        cancelToken: cancelToken,
      );

      stopwatch.stop();
      if (cancelKey != null) _cancelTokens.remove(cancelKey);

      final result = (
        _dioToResponse(response, 'POST', stopwatch.elapsedMilliseconds),
        null
      );

      _handleCallbacks(
        response: result.$1,
        error: result.$2,
        onSuccess: onSuccess,
        onError: onError,
        onHttpError: onHttpError,
        onStatus: onStatus,
        successCodes: successCodes,
        errorCodes: errorCodes,
      );

      return result;
    } else {
      final request = http.MultipartRequest('POST', Uri.parse(fullUrl));

      if (headers != null) request.headers.addAll(headers);
      if (fields != null) request.fields.addAll(fields);

      request.files
          .add(await http.MultipartFile.fromPath(fileField, filePath));

      final streamedResponse =
          await _http.send(request).timeout(timeout ?? config.sendTimeout);
      final response = await http.Response.fromStream(streamedResponse);

      stopwatch.stop();

      final result = (
        _httpToResponse(response, 'POST', stopwatch.elapsedMilliseconds),
        null
      );

      _handleCallbacks(
        response: result.$1,
        error: result.$2,
        onSuccess: onSuccess,
        onError: onError,
        onHttpError: onHttpError,
        onStatus: onStatus,
        successCodes: successCodes,
        errorCodes: errorCodes,
      );

      return result;
    }
  } catch (e) {
    stopwatch.stop();
    if (cancelKey != null) _cancelTokens.remove(cancelKey);
    final result = (null, _toException(e, fullUrl));

    _handleCallbacks(
      response: result.$1,
      error: result.$2,
      onSuccess: onSuccess,
      onError: onError,
      onHttpError: onHttpError,
      onStatus: onStatus,
      successCodes: successCodes,
      errorCodes: errorCodes,
    );

    return result;
  }
}