chopper icon indicating copy to clipboard operation
chopper copied to clipboard

How to I upload multipart image to server? I Tried every possible solutions reported in in issues but none helped :/

Open SalilLuley opened this issue 4 years ago • 14 comments

Below is the postman api.

Screenshot 2020-08-17 at 5 00 31 PM Screenshot 2020-08-17 at 5 02 21 PM

SalilLuley avatar Aug 17 '20 11:08 SalilLuley

Hi! Please try the https://stackoverflow.com/questions/59791332/upload-image-with-chopper answer

JEuler avatar Aug 22 '20 01:08 JEuler

@SalilLuley Also, take a look at this comment: https://github.com/lejard-h/chopper/issues/55#issuecomment-575107144

stewemetal avatar Aug 22 '20 06:08 stewemetal

I tried the above solutions, below is my api please check


  @Post(
    path: 'api/update',
    headers: {"application": "x-www-form-urlencoded'"},
  )
  @multipart
  Future<Response<BuiltProfilePictureResponse>> updateProfilePicture({
    @Part("field") String field,
    @PartFile("file") MultipartFile file,
    @Header("Authorization") String token,
  });

  static ProfileService create() {
    final client = ChopperClient(
        baseUrl: BASE_URL,
        services: [_$ProfileService()],
        converter: BuiltValueConverter(),
        interceptors: [
          HttpLoggingInterceptor(),
        ]);
    return _$ProfileService(client);
  }

Api call


  MultipartFile file = await MultipartFile.fromPath(
          'profile_picture', _image.path,
          contentType: new MediaType('image', 'jpg'));

      final response = await _profileService.updateProfilePicture(
          field: "profile_picture", file: file, token: "Bearer $token");

Still this throws error. :/

SalilLuley avatar Aug 23 '20 08:08 SalilLuley

Can you please share the error and stack trace you're getting? It would help us narrow down the possible causes. 😉

stewemetal avatar Aug 23 '20 10:08 stewemetal

If is throwing error in convertRequest method below on request.body. Says body is null.

Error Message E/flutter ( 1336): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: NoSuchMethodError: The getter 'types' was called on null. E/flutter ( 1336): Receiver: null E/flutter ( 1336): Tried calling: types

Below is the error SS. Screenshot 2020-08-25 at 11 07 35 AM

Built BuiltValueConverter class


class BuiltValueConverter extends JsonConverter {
  @override
  Request convertRequest(Request request) {
    return super.convertRequest(
      request.copyWith(
        // request.body is of type dynamic, but we know that it holds only BuiltValue classes (BuiltPost).
        // Before sending the request to the network, serialize it to a List/Map using a BuiltValue serializer.
        body: serializers.serializeWith(
          // Since convertRequest doesn't have a type parameter, Serializer's type will be determined at runtime
          serializers.serializerForType(request.body.runtimeType as Type),
          request.body,
        ),
      ),
    );
  }

  @override
  Response<BodyType> convertResponse<BodyType, SingleItemType>(
      Response response) {
    // The response parameter contains raw binary JSON data by default.
    // Utilize the already written code which converts this data to a dynamic Map or a List of Maps.
    final Response dynamicResponse = super.convertResponse(response);
    // customBody can be either a BuiltList<SingleItemType> or just the SingleItemType (if there's no list).
    final BodyType customBody =
        _convertToCustomObject<SingleItemType>(dynamicResponse.body)
            as BodyType;

    // Return the original dynamicResponse with a no-longer-dynamic body type.
    return dynamicResponse.copyWith<BodyType>(body: customBody);
  }

  dynamic _convertToCustomObject<SingleItemType>(dynamic element) {
    // If the type which the response should hold is explicitly set to a dynamic Map,
    // there's nothing we can convert.
    if (element is SingleItemType) return element;

    if (element is List)
      return _deserializeListOf<SingleItemType>(element);
    else
      return _deserialize<SingleItemType>(element as Map<String, dynamic>);
  }

  BuiltList<SingleItemType> _deserializeListOf<SingleItemType>(
    List dynamicList,
  ) {
    // Make a BuiltList holding individual custom objects
    return BuiltList<SingleItemType>(
      dynamicList.map((element) =>
          _deserialize<SingleItemType>(element as Map<String, dynamic>)),
    );
  }

  SingleItemType _deserialize<SingleItemType>(
    Map<String, dynamic> value,
  ) {
    // We have a type parameter for the BuiltValue type
    // which should be returned after deserialization.
    return serializers.deserializeWith<SingleItemType>(
      serializers.serializerForType(SingleItemType)
          as Serializer<SingleItemType>,
      value,
    );
  }
}

Below is the response class

abstract class BuiltProfilePictureResponse
    implements
        Built<BuiltProfilePictureResponse, BuiltProfilePictureResponseBuilder> {
  // fields go here
  @nullable
  int get status;
  // @nullable
  // BuiltProfilePictureResponseData get data;
  @nullable
  String get message;
  BuiltProfilePictureResponse._();

  factory BuiltProfilePictureResponse(
          [updates(BuiltProfilePictureResponseBuilder b)]) =
      _$BuiltProfilePictureResponse;

  static Serializer<BuiltProfilePictureResponse> get serializer =>
      _$builtProfilePictureResponseSerializer;
}

SalilLuley avatar Aug 25 '20 05:08 SalilLuley

simple just use dio man

misaelriojasftf avatar Oct 12 '20 05:10 misaelriojasftf

Having this same issue, any further resolutions?

BreSmit521 avatar Mar 20 '21 17:03 BreSmit521

Same fo me, any updates?

AntonIatsenko avatar May 13 '21 08:05 AntonIatsenko

Having this same issue, any further resolutions?

magician20 avatar Jul 05 '21 18:07 magician20

Having this same issue, any further resolutions?

Unfortunately, we ended up just doing this one specific call in Dio =\

BreSmit521 avatar Jul 05 '21 23:07 BreSmit521

It is working for me like that:

@Put(
      headers: {"Content-Type": "application/x-www-form-urlencoded"},
      path: 'path')
@multipart
Future<Response> uploadAvatar(@PartFile('file') http.MultipartFile file;
final file = http.MultipartFile.fromBytes('file', bytes,
      filename: file.path, contentType: MediaType('image', 'jpeg'));
uploadAvatar(file);      

JEuler avatar Jul 07 '21 12:07 JEuler

Guys? :)

JEuler avatar Jul 22 '21 10:07 JEuler

Guys? :)

Hey thanks for this! This does work with one exception, instead of using the http.MultipartFile I just had to import 'package:http/http.dart' show MultipartFile; due to the generated file not working correctly otherwise, just incase someone in the future sees this thread

Thanks!

BreSmit521 avatar Jul 22 '21 18:07 BreSmit521

I managed to get it working properly, you just need to use the following approach:

 @Post(
    path: '/test',
    headers: {
      'Content-Type': 'application/form-data',
    },
  )
  @Multipart()
  Future<Response<FileAddResponseModel>> uploadFileWithField(
    @Part('id') String id,
    @PartFile('file') MultipartFile file,
    @Part('description') String description,
  );

And when loading the file on controller, you should use it like that:

final file = await http.MultipartFile.fromPath(
      'file',
      localfile.path!,
    );

The localfile can be loaded as a PlatformFile.

Yke222 avatar Jun 05 '22 16:06 Yke222

Thanks all this works for me:

import 'dart:async';
import 'package:chopper/chopper.dart';
import 'package:http/http.dart' show MultipartFile; // <-- important

@ChopperApi(baseUrl: '')
abstract class MyApiService extends ChopperService {
  // ...

  @Post(
    path: '/api/books',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'multipart/form-data', // <-- important
    },
  )
  @Multipart()
  Future<Response<String>> storeBook({
    @Part('title') required String title,
    @Part('description') required String description,
    @PartFile('book_file') required MultipartFile bookFile,
  });

  // ...
}
import 'dart:io';

import 'package:chopper/chopper.dart';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';
import 'package:mime/mime.dart';

// ...
      // filePathStr = '/data/user/0/com.example.myapp/cache/file_picker/my-book.pdf';

      final bookFile = http.MultipartFile(
        'book_file',
        File(filePathStr).readAsBytes().asStream(),
        File(filePathStr).lengthSync(),
        filename: filePathStr.split('/').last,
        contentType: MediaType.parse(
          lookupMimeType(filePathStr) ?? '',
        ),
      );

      final response = await myApiService.storeBook(
        title: 'Title1',
        description: 'Description1',
        bookFile: bookFile,
      );
// ...

erlangparasu avatar Aug 25 '23 12:08 erlangparasu