I need to post a PDF file to a remote REST API, and I can't for the life of me figure it out. No matter what I do, the server responds that I have not yet associated an object with the file parameter. Let's say that I have a PDF called test.pdf. This is what I've been doing so far:
// Using an HttpClientRequest named req
req.headers.contentType = new ContentType('application', 'x-www-form-urlencoded');
StringBuffer sb = new StringBuffer();
String fileData = new File('Test.pdf').readAsStringSync();
sb.write('file=$fileData');
req.write(sb.toString());
return req.close();
Thus far, I've tried virtually every combination and encoding of the data that I write() to the request, but to no avail. I've tried sending it as codeUnits, I've tried encoding it using a UTF8.encode, I've tried encoding it using a Latin1Codec, everything. I'm stumped.
Any help would be greatly appreciated.
You can use MultipartRequest from the http package :
var uri = Uri.parse("http://pub.dartlang.org/packages/create");
var request = new http.MultipartRequest("POST", url);
request.fields['user'] = 'john#doe.com';
request.files.add(new http.MultipartFile.fromFile(
'package',
new File('build/package.tar.gz'),
contentType: new ContentType('application', 'x-tar'));
request.send().then((response) {
if (response.statusCode == 200) print("Uploaded!");
});
Try using the multipart/form-data header rather than x-www-form-urlencoded. This should be used for binary data, also can you show your full req request?
void uploadFile(File file) async {
// string to uri
var uri = Uri.parse("enter here upload URL");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// if you need more parameters to parse, add those like this. i added "user_id". here this "user_id" is a key of the API request
request.fields["user_id"] = "text";
// multipart that takes file.. here this "idDocumentOne_1" is a key of the API request
MultipartFile multipartFile = await http.MultipartFile.fromPath(
'idDocumentOne_1',
file.path
);
// add file to multipart
request.files.add(multipartFile);
// send request to upload file
await request.send().then((response) async {
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}).catchError((e) {
print(e);
});
}
I used file picker to pick file.
Here is the codes for pick file.
Future getPdfAndUpload(int position) async {
File file = await FilePicker.getFile(
type: FileType.custom,
allowedExtensions: ['pdf','docx'],
);
if(file != null) {
setState(() {
file1 = file; //file1 is a global variable which i created
});
}
}
here file_picker flutter library.
Related
Context: I need to send media templates in which I need to send local files. Thus I need to upload the files to the WhatsApp API to get the Media Id, which I can then use to send the message templates.
The issue: I am running into errors while sending the post request to the server through DART. However the same call is working when sent through postman. I have tried sending the data both as a JSON and as form-data, but both are returning errors. I am attaching the code below, as well as the errors I am facing. Any help is really appreciated.
Getting the file path
upload() async{
if(await Permission.storage.isGranted){
FilePickerResult? choice = await FilePicker.platform.pickFiles(allowMultiple: false);
String? path = choice?.files.single.path;
if(path != null){
uploadJson(path);
// uploadFormData(path);
}
}else{
Permission.storage.request();
}
}
Uploading JSON
uploadJson(String path) async{
File imgfile = File(path);
Uint8List imgbytes = await imgfile.readAsBytes();
String bs4str = base64.encode(imgbytes);
print(bs4str);
var headers = {
'Authorization': variables.authorizationToken,
"Content-Type": 'application/json',
};
var body = jsonEncode({
'file': '$bs4str;type=image/jpeg',
'messaging_product':'whatsapp'
});
Response response = await post(Uri.parse('${variables.baseURL}${variables.phoneNumberId}/media'), headers: headers, body: body);
print(response.body);
}
Uploading as Form-data
uploadFormData(String path) async {
var headers = {
'Authorization': 'Bearer EAAGtvNhUHUIBANf5KvyxnZCUKcRn3jTJgPZBR2AbbVhZBZBO7GjoDCnS26FQT6Nr6qdRV993ZCJEbGwiqZCdQ7TZBJX8S6KXQdOTgmSf9ue7GCEN1IL3yqfAUEIN1bw0nyvptHeZBFCsdfwpxZAcS1ZCbCdmqArZC81orVbYRkzJy1h7ChOAygmrchfFtJAapykZAadruFqOWwcVvtudMezse94zENBNVZA0k7pAZD',
};
var request = MultipartRequest('POST', Uri.parse('https://graph.facebook.com/v14.0/106822672107550/media'));
request.fields.addAll({
'messaging_product': 'whatsapp'
});
request.files.add(await MultipartFile.fromPath('file', path));
request.headers.addAll(headers);
Response response = await Response.fromStream(await request.send());
print(response.body);
}
Error for JSON:
flutter: {"error":{"message":"An unknown error has occurred.","type":"OAuthException","code":1,"fbtrace_id":"AE72st2KT8wJFQ_wYvrcJY6"}}
Error for Form-Data:
flutter: {"error":{"message":"(#100) Param file must be a file with one of the following types: audio\/aac, audio\/mp4, audio\/mpeg, audio\/amr, audio\/ogg, audio\/opus, application\/vnd.ms-powerpoint, application\/msword, application\/vnd.openxmlformats-officedocument.wordprocessingml.document, application\/vnd.openxmlformats-officedocument.presentationml.presentation, application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application\/pdf, text\/plain, application\/vnd.ms-excel, image\/jpeg, image\/png, image\/webp, video\/mp4, video\/3gpp. Received file of type 'application\/octet-stream'.","type":"OAuthException","code":100,"fbtrace_id":"AfsxKl38CW7hUF_ixMzNha9"}}
The problem was with the Mime-type of the file. The Multi-Part file class needed the mime-type of the file to be declared while uploading the file, or the file was automatically being uploaded as an octlet-stream. The code to the working request is posted below.
var request = http.MultipartRequest('POST', Uri.parse('https://graph.facebook.com/v14.0/${variables.phoneNumberId}/media'));
request.headers.addAll({
'Authorization': variables.authorizationToken,
'Content-Type': 'multipart/form-data'
});
request.fields.addAll({
'messaging_product': 'whatsapp',
'type': 'application/pdf'
});
// The MIME type of the image or file
const mimeType = 'application/pdf';
// Open the image file
var file = File(path);
// Create a MultipartFile from the File object
final multipartFile = await http.MultipartFile.fromPath(
'file',
file.path,
contentType: MediaType.parse(mimeType),
);
// Create a request body containing the multipart file
request.files.add(multipartFile);
// Send the request
final response = await request.send();
// Check the response status code
if (response.statusCode == 200) {
String body = await response.stream.bytesToString();
var json = jsonDecode(body);
print(json['id']);
} else {
print(response.reasonPhrase);
}
I want to upload a file using binary body like in the screenshot:
So far I just have:
save() async {
http.put(url,headers:headers, body: );
The body parameter of the put method accepts a List<int> that will be used as a list of bytes
From the http API reference: https://pub.dev/documentation/http/latest/http/put.html
body sets the body of the request. It can be a String, a List or
a Map. If it's a String, it's encoded using encoding
and used as the body of the request. The content-type of the request
will default to "text/plain".
If body is a List, it's used as a list of bytes for the body of the
request.
If body is a Map, it's encoded as form fields using encoding. The
content-type of the request will be set to
"application/x-www-form-urlencoded"; this cannot be overridden.
Examples to send a file:
main() async {
await put(url, body: File('the_file').readAsBytesSync());
}
You can use this for upload Image
Future uploadImage(File imageFile)async{
var stream= new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
var length= await imageFile.length();
var uri = Uri.parse("Image upload url");
var request = new http.MultipartRequest("POST", uri);
var filename = "Your image name";
var multipartFile = new http.MultipartFile("image", stream, length, filename: basename(filename));
request.files.add(multipartFile);
var response = await request.send();
if(response.statusCode==200){
print("Image Uploaded");
}else{
print("Upload Failed");
}
}
I've been searching in vain for a simple way of uploading a JSON file to a specific URL but I haven't been able to find one, for Flutter.
I have implemented the code to download a simple JSON file from a specific URL. What I haven't been able to find is how to upload the same file to same location.
Do I need to do the multipart stuff? And I'm not even sure how that works.
EDIT
I'm starting with Map data (Map) and I want to upload it to a server as JSON (text file). This code is specific to binary data. And yes, I'm just writing to a URL, not an endpoint:
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);
});
}
To upload files to an endpoint, you can use http.MultipartRequest - this allows you to upload files with binary content (images, docs, etc.) and files with regular text.
import 'package:http/http.dart' as http;
String url = // your endpoint
var req = http.MultipartRequest('POST', Uri.parse(url));
Then to upload
var request = http.MultipartRequest('POST', Uri.parse(url));
request.files.add(
await http.MultipartFile.fromPath(
'json',
filePath
)
);
var res = await request.send();
I'm looking for a way to convert Office files to PDF.
I found out that Microsoft Graph could be used.
I'm trying to download converted PDF using Microsoft Graph from OneDrive.
I'd like to convert .docx to .pdf.
However, when I sent the following request, I did not receive a response even if I waited.
GET https://graph.microsoft.com/v1.0/users/{id}/drive/root:/test.docx:/content?format=pdf
Also, the error code is not returned.
If syntax is wrong, an error code will be returned as expected.
It will not return only when it is correct.
In addition, I can download the file if I do not convert.
GET https://graph.microsoft.com/v1.0/users/{id}/drive/root:/test.docx:/content
Is my method wrong or else I need conditions?
If possible, please give me sample code that you can actually do.
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
client.BaseAddress = new Uri(graphUrl);
var result = await client.GetAsync("/v1.0/users/xxxxxxxxxxxxxxxxxxxxxxxxx/drive/root:/test.docx:/content?format=pdf");
:
I would like to elaborate a bit Marc's answer by providing a few examples for HttpClient.
Since by default for HttpClient HttpClientHandler.AllowAutoRedirect property is set to True there is no need to explicitly follow HTTP redirection headers and the content could be downloaded like this:
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.BaseAddress = new Uri("https://graph.microsoft.com");
var response = await client.GetAsync($"/v1.0/drives/{driveId}/root:/{filePath}:/content?format=pdf");
//save content into file
using (var file = System.IO.File.Create(fileName))
{
var stream = await response.Content.ReadAsStreamAsync();
await stream.CopyToAsync(file);
}
}
In case if follow HTTP redirection is disabled, to download the converted file, your app must follow the Location header in the response as demonstrated below:
var handler = new HttpClientHandler()
{
AllowAutoRedirect = false
};
using (HttpClient client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.BaseAddress = new Uri("https://graph.microsoft.com");
var response = await client.GetAsync($"/v1.0/drives/{driveId}/root:/{filePath}:/content?format=pdf");
if(response.StatusCode == HttpStatusCode.Redirect)
{
response = await client.GetAsync(response.Headers.Location); //get the actual content
}
//save content into file
using (var file = System.IO.File.Create(fileName))
{
var stream = await response.Content.ReadAsStreamAsync();
await stream.CopyToAsync(file);
}
}
The API doesn't return the converted content directly, it returns a link to the converted file. From the documentation:
Returns a 302 Found response redirecting to a pre-authenticated download URL for the converted file.
To download the converted file, your app must follow the Location header in the response.
Pre-authenticated URLs are only valid for a short period of time (a few minutes) and do not require an Authorization header to access.
You need to capture the 302 and make a 2nd call to the URI in the Location header in order to download the converted file.
I would like to know how can a server side application receive a file (via POST) and then print its contents on the server side.
The most "up to date" related question here was this one: Dart how to upload image
But it is not working anymore (Uncaught Error: type 'String' is not a subtype of type 'HttpBodyFileUpload' of 'fileUploaded').
EDIT:
This is how I send the file (this method is working fine):
import 'dart:html';
import 'dart:async';
HttpRequest request = new HttpRequest();
final _HOST = "127.0.0.1", _PORT = 8123;
Future sendFile(File file) {
var completer = new Completer(); // No need for a Completer. It will be removed.
Uri uri = new Uri(host: _HOST, port: _PORT);
request.open("POST", uri.toString());
var filename = file.name;
final FormData formData = new FormData();
formData.append('file', filename);
request.onLoadEnd.listen((_) {
completer.complete(request.response);
});
request.send(formData);
return completer.future;
}
The server side (I'm stuck here):
void _handlePost(HttpRequest req) {
HttpBodyHandler.processRequest(req).then((body) {
HttpBodyFileUpload fileUploaded = body.body['file'];
print(fileUploaded.content);
});
}
You are appending the filename instead of the Blob (File) to your FormData object. In Dart it looks like there is a special function for appending blobs called appendBlob(name, blob, [filename]).