Cant upload file with multipartform in SwiftUI - swiftui

I'm trying to upload a file in swiftUI, using multipart form-data
The code is like this:
do {
let data = try Data(contentsOf: url)
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(data, withName: "uploadedFile",fileName: "uploadedFile",mimeType: "text/plain")
}, to: "https://server.com/upload",headers: ["Authorization" : "Bearer \(API.shared.accessToken!)",
"Content-Type": "multipart/form-data"])
.responseDecodable(of: String.self ) { response in
debugPrint(response)
}
}
catch {
print("Error \(error)")
}
Where url is a local URL, DocumentPickerViewController has provided.
For some reason the server gives an error saying something went wrong.
This is the response I picked up in Charles:
And this the response I picked up in Postman (which works):
I noticed that postman automatically generated the Content type parameter in the formdata (which was an image in this test, but it could be any file type). Alamofire didn't do that by default, so I added filename and the mimetype (text/plain) in the request, but that didn't work.
Any thoughts? It works on Postman. So is this a server issue or a frontend issue?

This code worked for me , for uploading an image file
I used "application/x-www-form-urlencoded" instead of "Content-Type": "multipart/form-data"
let url = "url here"
let headers: HTTPHeaders = [
"Authorization": "Bearer Token Here",
"Accept": "application/x-www-form-urlencoded"
]
AF.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(imageData, withName: "image" ,fileName: "image.png" , mimeType: "image/png")
}, to: url, method: .post ,headers: headers).validate(statusCode: 200..<300).response { }

Related

How to make subsequent request to SAP Business One Service Layer from Django

I want to use Django to make requests to SAP Business One Service Layer. SAP B1 Service Layer requires initial login to establish a session. I am able to authenticate and get a correct response with a returned session ID from the Service Layer. There is a 30 minute timeout after successful login if there is no activity. How can I save a session from another server (in this case the Service layer) to make additional requests? Below is code of the initial SAP post request to the Login endpoint.
def AuthSAP(request):
sap_url = "https://sap_url.com:50000/b1s/v2/Login"
headers = {
"authkey": "XXXXXXXXXXXXXXXXXXXX",
"Accept": "*/*",
"Content-Type": "text/plain",
}
data = {
"CompanyDB": "XXXXXXXX",
"UserName": "XXXXXXXX",
"Password": "XXXXXXX"
}
response = requests.post(sap_url, headers=headers, json=data)
print("JSON Response ", response.json())
return HttpResponse(response.json(), content_type='application/json')
When I make additional request to the Service Layer I get an error from the JSON Response. Any insight or suggestions is much appreciated. Thank you.
For example, if I make another request to any other end point I will get the error message below (GET https://sap_url.com:50000/b1s/v2/Orders).
/* Subsequent Calls require header info with authkey. Body not needed */
def GetOpenOrders(request):
sap_url = "https://sap_url.com:50000/b1s/v2/Orders"
headers = {
"authkey": "XXXXXXXXXXXXXXXXXXXX",
"Accept": "*/*",
"Content-Type": "text/plain",
}
response = requests.get(sap_url, headers=headers)
print("JSON Response ", response.json())
return HttpResponse(response.json(), content_type='application/json')
JSON Response {'error': {'code': '301', 'message': 'Invalid session or session already timeout.'}}
I found a work around to this question and I hope it can help someone looking for a similar answer.
What I did was save the "SessionId" from the Login request and then add it to the "Cookie" inside the header. So subsequent request will have "Cookie" inside the header. I saw this as a workaround when I used Postman and saw the "Cookie" key and value in the header.
def GetOpenOrders(request):
sap_url = "https://sap_url.com:50000/b1s/v2/Orders"
headers = {
"Cookie": "B1SESSION=SessionID; ROUTEID",
"authkey": "XXXXXXXXXXXXXXXXXXXX",
"Accept": "*/*",
"Content-Type": "text/plain",
}
response = requests.get(sap_url, headers=headers)
print("JSON Response ", response.json())
return HttpResponse(response.json(), content_type='application/json')
I manually tested by copy and pasting the SessionId to the "Cookie" value. You would need to store the SessionId and pass it as a variable.

Error while uploading image on AWS S3 - with Axios & React-Native

I'm trying to upload an image from my Mobile App (with React-Native) on AWS S3 with a presigned URL. I'm using axios to send the request.
The problem is that even if my image is uploaded on AWS, if I download it and try to open it says it's corrupted. I tried to open with Photoshop and it works :/
Creating the formData:
const createFormData = (photo) => {
const data = new FormData();
data.append('image', {
name: photo.fileName, // a name
type: photo.type, // image/jpg
uri: photo.uri, // the uri starting with file://....
});
return data;
};
My PUT request:
const formData = createFormData(responseImage)
axios({
method: "put",
url: awsURL.data.url_thumbnail,
data: formData,
headers: { "Content-Type": "multipart/form-data" },
})
This isn't how it works.
headers: { "Content-Type": "multipart/form-data" }
The content-type multipart/form-data also contains a field called boundary separated by a delimiter. You can get more details here. The article has the details for the format of boundary.
Another example for the same.
Hope it helps!
PS: There are some articles related to parsing data for multipart/form-data that I can't find right now, which explain how to parse the data before uploading so that the data isn't corrupted.

Uploaded file to S3 via PreSigned URL from Flutter App. but the file is corrupted when i download it

I am working on a Flutter App, where I upload image file (PUT Request) to AWS S3 using a presigned URL. The upload is successful as I can see the file in S3. But when I click and download it from the bucket, the downloaded file is corrupted.
I am using Dio library for uploading the file.
Uploading the image file as binary via postman works perfectly
uploadFileToPresignedS3(
File payload, String fileName, String presignedURL) async {
try {
Dio dio = new Dio();
FormData formData = new FormData.from(
{"name": fileName, "file1": new UploadFileInfo(payload, fileName)});
dio.put(presignedURL, data: formData);
} catch (ex) {
print(ex);
}
}
Expected: The uploaded file not to be corrupted
Actual result: The uploaded file is corrupted
Use this code to upload file (image) to S3 pre-signed-url using Dio and show upload progress:
await dio.put(
url,
data: image.openRead(),
options: Options(
contentType: "image/jpeg",
headers: {
"Content-Length": image.lengthSync(),
},
),
onSendProgress: (int sentBytes, int totalBytes) {
double progressPercent = sentBytes / totalBytes * 100;
print("$progressPercent %");
},
);
Note: Do not set Content-Type header along with Content-Length like this:
headers: {
"Content-Length": image.lengthSync(),
"Content-Type": "image/jpeg",
},
Due to some reason, it will result in corrupted uploaded file.
Just in case: Instead of print("$progressPercent %") you can use setState() to show updates in UI.
Hope this helps.
To piggy back off of Rabi Roshans's comment you need to modify contenType to "application/octet-stream". In your backend's S3 params you need to do the same.
client code
await dio.put(
url,
data: image.openRead(),
options: Options(
contentType: "application/octet-stream",
headers: {
"Content-Length": image.lengthSync(),
},
),
onSendProgress: (int sentBytes, int totalBytes) {
double progressPercent = sentBytes / totalBytes * 100;
print("$progressPercent %");
},
);
s3 backend
var presignedUrl = s3.getSignedUrl("putObject", {
Bucket: "your_bucke_name",
Key: "filename.ext",
Expires: 120, // expirations in seconds
ContentType: "application/octet-stream", // this must be added or you will get 403 error
})
;
I created this class to send an image to s3 using pre-signed url, I'm using camera lib to send a photo to s3.
import 'dart:convert';
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:http/http.dart';
import 'package:http_parser/http_parser.dart';
class AwsApi {
Future<String> uploadToSignedUrl({required XFile file, required String signedUrl}) async {
Uri uri = Uri.parse(signedUrl);
var response = await put(uri, body: await file.readAsBytes(), headers: {"Content-Type": "image/jpg"});
return response;
}
}

Request failure with django API and Alamofire

Requests with Alamofire 4 in Swift 3 always fails with 500 status code. I tryed in Postman and works!
Look at my code:
func newUser(user: User) {
var urlRequest = URLRequest(url: URL(string: url + "/register")!)
urlRequest.httpMethod = "POST"
let parameters: Parameters = [
"username": "\(user.name!)",
"email": "\(user.email!)",
"password": "(Kh=CE)4r)PC4}f?",
"profile": [
"status": 0,
"level": 0,
"facebook_id": "\(user.fbId!)",
"facebook_token": "000",
"push_device_token": "000",
"photo": "\(user.photoUrl!)"
]
]
let headers: HTTPHeaders = ["Content-Type": "application/json"]
Alamofire.request(url+"/register", method: .post, parameters: parameters, encoding: JSONEncoding(options: []), headers: headers).response { response in
debugPrint(response)
print(response)
}
}
Anyone can help me?
I have done the same thing you are trying to accomplish and the only difference I see is your header, try changing it to:
let headers = ["Authorization": )", password]
Wireshark can also help you to see the exact reason for the 500 error.

Facebook video upload invalid foramat. It should be an image file data

Here I am trying to upload a video to user profile.
I have set up javascript sdk and my authentication works well .
I have the following code here..
FB.api(
`/${user_id}/videos`,
"POST",
{
"file_url": video,
"description": description,
"thumb": video_thumbnail,
"title": title,
},
function (response) {
console.log("fb response")
console.log(response)
if (response && !response.error) {
/* handle the result */
console.log("video upload response")
console.log(response)
}
});
Here I get the following error ..
code: 100
fbtrace_id: "FD5tVyrH9bS"
message: "(#100) Invalid format. It should be an image file data."
type: "OAuthException"
I am using file_url and passing url to my video. I guess it should upload the video..
Thank you for the response
I confirm that you must post image file data in source field when posting to Facebook.
You can test by use Postman.
This is example:
var fs = require("fs");
var request = require("request");
var options = { method: 'POST',
url: 'https://graph.facebook.com/v2.11/2011156779127713/thumbnails',
headers:
{ 'Postman-Token': '6c17c103-d8f6-47a5-713b-b3709dde762d',
'Cache-Control': 'no-cache',
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' },
formData:
{ access_token: 'test',
is_preferred: 'true',
source:
{ value: 'fs.createReadStream("./Downloads/923249_818835191462845_1528674847924045075_n.jpg")',
options:
{ filename: './Downloads/923249_818835191462845_1528674847924045075_n.jpg',
contentType: null } } } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
The problem isn't the video or the URL, it's the thumb parameter.
The thumb parameter needs to be 'file data', not the URL.
As to what format the image needs to be in..please let me know if you find out! I'm asking the same here.
The facebook API is terrible...