How to send files in flutter - flutter

I am trying to send files to server with flutter but it return this error:
Unhandled Exception: type 'List<File>' is not a subtype of type 'String' in type cast
Code
I've commented code below for better understanding
late List<File> newDoc = [];
// Select files
ElevatedButton(
onPressed: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: true
type: FileType.custom,
allowedExtensions: ['jpg', 'pdf', 'doc', 'docx', 'ppt', 'pptx'],
);
if(result != null) {
// Not sure if I should only get file path or complete data (this was in package documentation)
List<File> files = result.paths.map((path) => File(path!)).toList();
newDoc = files;
} else {
// User canceled the picker
}
},
child: Text('Select Files'),
),
SizedBox(height: 15.0),
// Send files to server
ElevatedButton(
onPressed: () async {
//save
var response = await http.post(
Uri.parse('https://example.come/upload/${args.id}'),
body: {
'documents': newDoc, // send array of my selected files to server
},
headers: {
HttpHeaders.authorizationHeader: '$userToken',
HttpHeaders.acceptHeader: 'application/json'
},
);
print('request::: $response');
// if (response.statusCode == 200) {
// .....
// } else {
// .....
// }
//save
},
child: Text('Save'),
),
Any suggestions?
Update
I've changed my http request to code below but my server receives empty body (the request does not send my files to backend)
var request = http.MultipartRequest('POST', uri);
request.headers['authorization'] = '$userToken';
request.headers['acceptHeader'] = 'application/json';
newDoc.map((k) async {
request.files.add(await http.MultipartFile.fromPath(
'documents', k.path
));
});
var response = await request.send();
var response2 = await http.Response.fromStream(response);
print('request::: ${response2.statusCode}');
print('request::: ${response2.body}'); // return as []

You have to use MultipartRequest to upload files. For example:
var uri = Uri.parse('https://example.com/create');
var request = http.MultipartRequest('POST', uri)
..fields['user'] = 'nweiz#google.com'
..files.add(await http.MultipartFile.fromPath(
'package', 'build/package.tar.gz',
contentType: MediaType('application', 'x-tar')));
var response = await request.send();
if (response.statusCode == 200) print('Uploaded!');
So for you it is like that:
final request = net.MultipartRequest("post", Uri.parse("https://example.come/upload/${args.id}"));
for (final file in files) {
request.files.add(await MultipartFile.fromPath(file.uri.pathSegments.last, file.path));
}
request.headers[HttpHeaders.authorizationHeader] = '$userToken';
request.headers[HttpHeaders.acceptHeader] = 'application/json';
final response = await request.send();
file.uri.pathSegments.last is a file name.

Your post call should look like this
var response = await http.post(
Uri.parse('https://example.come/upload/${args.id}'),
body: {
'documents': newDoc.map((e) => e.path).toList().join(', '),
},
headers: {
HttpHeaders.authorizationHeader: '$userToken',
HttpHeaders.acceptHeader: 'application/json'
},
);
The newDoc variable is List of Files, so convert the List of files to list of Strings (paths) using newDoc.map((e) => e.path).toList().join(', ')

Related

Image network did not change after uploading the image (flutter)

So, i make a feature to change profile pic. uploading successfully, then i try to get the new pict, but the pict is null because when i print the pict it shows the older pict instead of a new one.
seems like the image network didn't update automatically.
anybody can explain why this happen and how to fix it?
code for uploading
Future upload(File imageFile) async {
var stream = http.ByteStream(imageFile.openRead());
stream.cast();
var length = await imageFile.length();
String uuid = await UserPreference().getUuid();
var uri = Uri.parse("$baseUrl/customer/$uuid");
var request = http.MultipartRequest("POST", uri);
var multipartFile = http.MultipartFile('profile_picture', stream, length,
filename: basename(imageFile.path));
String getToken = await UserPreference().getToken();
request.headers.addAll({
'Content-Type': 'application/json',
HttpHeaders.authorizationHeader: "Bearer $getToken"
});
request.files.add(multipartFile);
var response = await request.send();
print(getToken);
if (response.statusCode == 200) {
print('uploaded');
} else {
print('failed');
}
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
the way i call the pic is
CircleAvatar(
radius: 50,
child: Image.network(
user.profile_picture!,
fit: BoxFit.cover,
),
),
Add setState once after response.
void uploadImage() async {
// Show loader
// open a byteStream
var stream = new
http.ByteStream(DelegatingStream.typed(file.openRead()));
// get file length
var length = await file.length();
Map<String, String> headers = {
"Accept": "application/json",
"Authorization": token
}; // ignore this headers if there is no authentication
// string to uri
var uri = Uri.parse(Constants.BASE_URL);
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// if you need more parameters to parse, add those like this
// to the API request
request.fields["orderId"] = orderID.toString();
// multipart that takes file.. here this "file" is a key of the
// API request
var multipartFile = new http.MultipartFile('file', stream,
length,
filename: basename(file.path));
//add headers
request.headers.addAll(headers);
// add file to multipart
request.files.add(multipartFile);
// send request to upload image
await request.send().then((response) async {
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
setState(() {
if (response.statusCode == 200) {
print('uploaded');
} else {
print('failed');
}
});
// Hide loader
});
}).catchError((e) {
print(e);
// Hide loader
});
This will refresh the UI.

Converting object to an encodable object failed: Instance of '_File' Flutter

I'm trying to post an image to API.
This is my Post Function :
Future<http.Response> ajoutProduit(
String refProduit,
String nomProduit,
double prixAchatProduit,
double prixVenteProduit,
String descriptionProduit,
File imageProduit) async {
List produits = [];
final response = await http.post(
Uri.parse('http://127.0.0.1:8000/api/produit/'),
headers: <String, String>{'Content-Type': 'multipart/form-data'},
body: jsonEncode(<String, dynamic>{
'refProd': refProduit,
'nomProd': nomProduit,
'prixAchat': prixAchatProduit,
'prixVente': prixVenteProduit,
'descriptionProd': descriptionProduit,
'imageProd': imageProduit,
}),
);
if (response.statusCode == 200) {
return produits = jsonDecode(response.body);
} else {
throw Exception('Erreur base de données!');
}
}
and this is my ImagePicker function :
File uploadimage;
Future<void> chooseImage() async {
final ImagePicker picker = ImagePicker();
var choosedimage = await picker.pickImage(source: ImageSource.gallery);
final File convertimage = await File(choosedimage.path);
setState(() {
uploadimage = convertimage;
});
}
Finally, this is the confirm button :
ElevatedButton(
onPressed: (() {
if (_formKey.currentState.validate()) {
setState(() {
future = ajoutProduit(
refProduit.text,
nomProduit.text,
double.parse(prixAchatProduit.text),
double.parse(prixVenteProduit.text),
descriptionProduit.text,
uploadimage);
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Produit Ajouté')),
);
Navigator.of(context, rootNavigator: true).pop();
}
}), ...
When i press the button i get this error in the debug console :
Error: Converting object to an encodable object failed: Instance of '_File'
I would suggest uploading the file as form you can do something like the following
List<http.MultipartFile> files = [await http.MultipartFile.fromPath('file', file.path)];
http.MultipartRequest request = new http.MultipartRequest("POST", uri);
for (http.MultipartFile file in files) {
request.files.add(file);
}
http.StreamedResponse responseStream = await request.send();
http.Response response = await
http.Response.fromStream(responseStream).timeout(Duration(seconds: timeoutSeconds));

Flutter: I am uploading a file to database using post api. But it gives me a bug

I am using file picker to pick the file. The file can be png jpg or pdf.
FilePickerResult? result =
await FilePicker.platform.pickFiles(
type: FileType.custom,
allowMultiple: true,
allowedExtensions: ['jpg', 'png', 'pdf'],
allowCompression: true,
);
setState(() {
if (result!.files.length != 0) {
_con!.thumbnail = result.files;
}
});
And the following is the code for uploading it to the database using post api using Dio library
Future uploadFile(BuildContext context) async {
setState(() {
isFormLoading = true;
});
var R;
Dio D = Dio();
D.options.headers = {
'Content-type': 'multipart/form-data',
// 'Content-type': 'application/json',
'Accept': 'application/json',
};
FormData formData = FormData.fromMap({
"image": DD.MultipartFile.fromFile(thumbnail.elementAt(0).path!),
});
R = await D.post(BASE_URL + "api/v2/upload/21", data: formData);
dynamic Response = R.data;
print('Response is >>>>>>');
print(R);
// BotToast.showText(text: Response["success"].toString());
setState(() {
isFormLoading = false;
});
}
modify the extension of the upload file file (jpg, png, pdf)
var formData = FormData.fromMap({
"file":
await MultipartFile.fromFile(path, filename: 'upload.jpg'),
});
Response response = await dio.post(
Constant().urlBase + Constant().confirm_package_reception,
data: formData);`enter code here`

Invalid request payload input on flutter post request

I am trying to uploading multiple files from my flutter mobile app. Here is my screenshot of the postman. This works fine on postMan. But I am getting 400 errors on the flutter mobile app. I can't find out where is the problem?
Now here is the code of my flutter mobile app upload.
if(images.length>0){
for (int i = 0; i < images.length; i++) {
var path = await FlutterAbsolutePath.getAbsolutePath(images[i].identifier);
String fileName = path.split('/').last;
var file = await MultipartFile.fromFile(path, filename:fileName);
multipart.add(file);
}
FormData imageFormData = FormData.fromMap(
{
"feedId": value.id,
"images": multipart,
"userInformationsId": value.userInformationId
});
print(multipart.length);
uploadFeedPicture(imageFormData);
}
Future<String> uploadFeedPicture(FormData _imageformData) async{
String at = await _apiProvider.getAccessToken();
Dio dio = new Dio();
// dio.options.headers['accept'] = 'application/json';
// dio.options.headers["content-Type"] = "multipart/form-data";
dio.options.headers["Authorization"] = "Bearer ${at}";
dio.options.baseUrl = getBaseUrl();
var _baseUrl = getBaseUrl();
await dio.post('/api/feed/upload', data: _imageformData, options: Options(
followRedirects: false,
validateStatus: (status) { return status < 500; }
), onSendProgress: (int sent, int total) {
print("$sent $total");
},).then((value) {
print(value.data);
print(value.headers);
}
).catchError((error) => print(error) );
}
And I am getting this response.
{statusCode: 400, error: Bad Request, message: Invalid request payload input}
Please Help me out where is the problem? I try with change content-type but not working.
After trying so many different ways I found the solution. Here it is.
if(value.id != null){
String at = await _apiProvider.getAccessToken();
Map<String, String> headers = { "Authorization": "Bearer ${at}"};
var uri = Uri.parse('$baseUrl/api/feed/upload');
var request = http.MultipartRequest('POST', uri);
request.headers.addAll(headers);
if(images.length>0){
for (int i = 0; i < images.length; i++) {
var path = await FlutterAbsolutePath.getAbsolutePath(images[i].identifier);
// String fileName = path.split('/').last;
var file = await MultipartFile.fromPath("images",path);
request.files.add(file);
}
request..fields['feedId'] = value.id;
request..fields['userInformationsId'] = value.userInformationId;
var response = await request.send();
if (response.statusCode == 200) {
Navigator.pop(context);
showSuccessToast("Posted succesfull");
counter.update(0);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}else{
showErrorToast("Upload image failed");
}
}
}

How to upload images to server in Flutter?

I would like to upload a image, I am using http.Client() for making requests,
static uploadImage(String id, File file) {
var httpClient = createHttpClient();
Map<String, String> headers = new Map<String, String>();
headers.putIfAbsent("Authorization", () => "---");
headers.putIfAbsent("Content-Type", () => "application/json");
var body=new List();
body.add(id.)
httpClient.post(URL_UPLOADIMAGE,headers: headers,body: ,encoding: )
}
What should be the body and encoding part for the request ?
Use MultipartRequest class
Upload(File imageFile) async {
var stream = new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
var length = await imageFile.length();
var uri = Uri.parse(uploadURL);
var request = new http.MultipartRequest("POST", uri);
var multipartFile = new http.MultipartFile('file', stream, length,
filename: basename(imageFile.path));
//contentType: new MediaType('image', 'png'));
request.files.add(multipartFile);
var response = await request.send();
print(response.statusCode);
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
name spaces:
import 'package:path/path.dart';
import 'package:async/async.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
The easiest way is to use the http library,
import 'dart:io';
import 'package:http/http.dart' as http;
_asyncFileUpload(String text, File file) async{
//create multipart request for POST or PATCH method
var request = http.MultipartRequest("POST", Uri.parse("<url>"));
//add text fields
request.fields["text_field"] = text;
//create multipart using filepath, string or bytes
var pic = await http.MultipartFile.fromPath("file_field", file.path);
//add multipart to request
request.files.add(pic);
var response = await request.send();
//Get the response from the server
var responseData = await response.stream.toBytes();
var responseString = String.fromCharCodes(responseData);
print(responseString);
}
Checkout the body in submitForm() method.
File _image;
Future cameraImage() async {
var image = await ImagePicker.pickImage(
source: ImageSource.camera,
maxHeight: 240.0,
maxWidth: 240.0,
);
setState(() {
_image = image;
});
}
submitForm() async {
final response = await http.post(
uri,
headers: {
AuthUtils.AUTH_HEADER: _authToken
},
body: {
'user_id': userId
'photo': _image != null ? 'data:image/png;base64,' +
base64Encode(_image.readAsBytesSync()) : '',
},
);
final responseJson = json.decode(response.body);
print(responseJson);
}
I have tried all the above but none worked for me to upload a file to a server.
After a deep search, I got a plugin the same as Dio.
The following code uploads a file to a server.
uploadFileFromDio(UserProfile userProfile, File photoFile) async {
var dio = new Dio();
dio.options.baseUrl = url;
dio.options.connectTimeout = 5000; //5s
dio.options.receiveTimeout = 5000;
dio.options.headers = <Header Json>;
FormData formData = new FormData();
formData.add("user_id", userProfile.userId);
formData.add("name", userProfile.name);
formData.add("email", userProfile.email);
if (photoFile != null &&
photoFile.path != null &&
photoFile.path.isNotEmpty) {
// Create a FormData
String fileName = basename(photoFile.path);
print("File Name : $fileName");
print("File Size : ${photoFile.lengthSync()}");
formData.add("user_picture", new UploadFileInfo(photoFile, fileName));
}
var response = await dio.post("user/manage_profile",
data: formData,
options: Options(
method: 'POST',
responseType: ResponseType.PLAIN // or ResponseType.JSON
));
print("Response status: ${response.statusCode}");
print("Response data: ${response.data}");
}
I found a working example without using any external plugin , this
only uses
import 'package:http/http.dart' as http;
Code
var stream =
new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
// get file length
var length = await imageFile.length(); //imageFile is your image file
Map<String, String> headers = {
"Accept": "application/json",
"Authorization": "Bearer " + token
}; // ignore this headers if there is no authentication
// string to uri
var uri = Uri.parse(Constants.BASE_URL + "api endpoint here");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// multipart that takes file
var multipartFileSign = new http.MultipartFile('profile_pic', stream, length,
filename: basename(imageFile.path));
// add file to multipart
request.files.add(multipartFileSign);
//add headers
request.headers.addAll(headers);
//adding params
request.fields['loginId'] = '12';
request.fields['firstName'] = 'abc';
// request.fields['lastName'] = 'efg';
// send
var response = await request.send();
print(response.statusCode);
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
Please try below solution
Future<String> uploadImageHTTP(file, url) async {
var request = http.MultipartRequest('POST', Uri.parse(url));
request.files.add(await http.MultipartFile.fromPath('picture', file.path));
var res = await request.send();
return res.reasonPhrase;
}
Consider using Flutter's Firebase Storage plugin -- it has features that could be useful for uploading large image files on a mobile connection.
I wrote the plugin, contributions and feedback are welcome!
First of all choose your image from gallery or Camera
File _image;
Future _getImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_image = image;
});
}
Now call the below function on button click or inside the _getImage() function. With the file i'm uploading other fields also you see in the saveInAttendance()
Don't forget to import package :
import 'package:dio/dio.dart';
import 'package:path/path.dart';
Future saveInAttendance( BuildContext context,String entryType,String mode) async {
Dio dio = new Dio();
FormData formData = new FormData(); // just like JS
formData.add("inimageFile", new UploadFileInfo(_image, basename(_image.path)));
formData.add("compID",2);
formData.add("company_id",2);
formData.add("EntryType", entryType);
formData.add("emp_code", 5);
formData.add("Mode",mode);
formData.add("location",""+_startLocation.latitude.toString()+"-"+_startLocation.longitude.toString());
dio.post(url_save_attendance, data: formData, options: Options(
method: 'POST',
responseType: ResponseType.json // or ResponseType.JSON
))
.then((r) {
setState(() {
var data = json.decode(r.toString());
if(data["apiMessage"].contains('Saved')){
warningAlert("Attendance Saved", "Your attendance saved Successfully",context);
}
});
}).catchError(print);
}
For more Info you can visit Here
my working code below, based on #TejaDroid's sample,
it upload one image via the AWS Gateway API with a lambda function behind to store the image into S3.
uploadImageWithhttp(File imageFile, int serialno) async {
var postBody= {
'username': 'test#gmail.com',
"productid": "1000123", //TODO
"imageno": serialno.toString(),
'image': imageFile != null ? base64Encode(imageFile.readAsBytesSync()) : '',
};
final response = await http.post(
constAWSAPIGateway_UploadImage[CONST_API_STAGE],
headers: {
//AuthUtils.AUTH_HEADER: _authToken
'Content-Type' : 'application/json',
},
body: json.encode(postBody),
);
final responseJson = json.decode(response.body);
print(responseJson);
}
to get Body from request Instead of
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
I use:
String body=await response.stream.bytesToString()
updateProfile() async {
try {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
var dio = new Dio();
var formData = FormData.fromMap({
'name': name,
'con_person_name': concernedPersonName,
'email': email,
'phone': phoneNumber,
'password': password,
'token': token,
'user_type': '3',
'license_no': licenceNumber,
'gstno': gstNumber,
'address': address,
'hospital_id': '102'
'image': await MultipartFile.fromFile(_image?.path,
filename: _image.path.split('/').last ?? 'image.jpeg'),
});
var response = await dio.post('$SERVER_ADDRESS/api/doctorregister',
data: formData);
print(response.statusCode);
print(response.data);
}
} catch (error) {
print(error.toString());
}
}
Import dio, image_picker library
Future _onGalleryPressed() async {
Future<File> image = ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
this._imageFile = image;
});
File img = await image;
Navigator.of(context).pop();
if (img != null) {
//API CALL
try {
FormData formData = new FormData.from({"file": path});
var url = backendUrl + "/upload-image";
var token = await _getMobileToken();
Map<String, String> headers = {
'Authorization': 'Bearer $token',
"Content-Type": "multipart/form-data",
"X-Requested-With": "XMLHttpRequest"
};
await dio.post(url,
data: formData,
options: Options(
method: 'POST',
headers: headers,
responseType: ResponseType.json // or ResponseType.JSON
));
Navigator.pop(context);
} catch (e) {}
}
}
If you want to upload it as a binary file.
static uploadFile(File imageFile) async {
final response = await http.post(postURL, body: imageFile.readAsBytesSync());
return json.decode(response.body);
}
Thank you
I have checked about it at multiple places finally i found a solution -
var objToSend = {
"file": await MultipartFile.fromFile(
file.path,
filename: filename,
),
};
FormData formData = FormData.fromMap(objToSend);
print(formData.files.toString());
Dio dio = new Dio();
await dio
.post(_toSend,
data: formData,
options: Options(
method: 'POST',
headers: <String, String>{
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Authorization": 'Bearer ' + token
},
))
.whenComplete(() {
print('uploaded');
}).catchError((onError) {
print('failed');
});
I have found a easy way to upload images in flutter and then even receiving it on the server.
Flutter:
MaterialButton(
color: Colors.blue,
child: Text(
"Pick Image from Camera",
style: TextStyle(
color: Colors.white70, fontWeight: FontWeight.bold),
),
onPressed: () async {
final XFile? photo =
await _picker.pickImage(source: ImageSource.camera);
print(photo!.path);
await uploadImage(photo.path);
},
),
'uploadImage' function:
uploadImage(String filepath) async {
var url = 'http://192.168.75.57:4000/upload';
var request = http.MultipartRequest('POST', Uri.parse(url));
request.files.add(await http.MultipartFile.fromPath("img", filepath));
request.fields['_id'] = "abcdef";
request.headers.addAll({
"Content-type": "multipart/form-data",
});
var response = request.send();
return response;
}
On the server Side: (Nodejs)
For this, first install multer (npm install multer)
const multer = require('multer');
const path = require('path')
const storage = multer.diskStorage({
destination: './uploads',
filename: (req, file, cb) => {
cb(null, (new Date()).getTime().toString() + ".jpg");
},
});
const fileFilter = (req, file, cb) => {
if (file.mimetype == "image/jpeg" || file.mimetype == "image/png") {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 6,
},
fileFilter: fileFilter,
});
Finally, honoring the request from flutter application:
(In router.js)
router.post('/upload', upload.single("img"), function (req, res) {
console.log("hit")
console.log(req.body._id)
res.send("ok")
})
This method worked for me and I found it comparatively easier than other methods.