using Alamofire 5 to upload file to RocketChat server - swift

I'm using Alamofire 5, and I'm trying to upload an image to a Rocket Chat server. The corresponding curl statement that I need to duplicate using AF is at the following link:
(link to documentation: https://docs.rocket.chat/api/rest-api/methods/rooms/upload)
I've been trying to upload using multipartFormData with no success. I've also attempted to bypass Alamofire altogether and use Swift URLSession. The best I can do is get the same error message from the server, which is "errorType": invalid-field."
My code as it stands right now:
let url = URL_MESSAGES + "rooms.upload/\(_group._id ?? "")"
let boundary = UUID().uuidString
let headers: HTTPHeaders = [
"X-Auth-Token": authToken,
"X-User-Id": me._id ?? "",
"Content-type":"multipart/form-data; boundary=\(boundary)"
]
if let data = image.jpeg(.medium) {
print(data.count)
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(data, withName: "image", fileName: "image.jpeg", mimeType: "image/jpeg")
},
to: url, method: .post , headers: header)
.response { resp in
print(resp)
}
.cURLDescription { description in
print(description)
}
.responseString { [weak self] (response) in
DispatchQueue.main.async {
if response.error == nil {
guard let data = response.data else {
return completion(true,[:])
}
if let json = try? JSON(data: data) {
let dictionaryIn = json.rawValue as! [String : Any]
if (self?.isSuccess(data: dictionaryIn))! {
completion(true,json.rawValue as! [String : Any])
}else{
completion(false,[:])
self?.handleError(data: dictionaryIn)
}
}
}else{
completion(false,[:])
self?.handleError(data: [:])
}
}
}
}
}

I think you're breaking the upload by trying to set your own boundary. Alamofire will that for you automatically. Try removing the header.

The above code works perfectly, when I changed this:
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(data, withName: "image", fileName: "image.jpeg", mimeType: "image/jpeg")
to:
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(data, withName: "file", fileName: "image.jpeg", mimeType: "image/jpeg")
Swapping out "image" for "file" fixed everything. I went with "image" because this is what every Alamofire tutorial I could find said to do. However, RocketChat requires it to be "file". It is in the documentation, but I didn't realize that's what it was telling me to do. Specifically, in the documentation, it says:
"Note: For some file types if uploading via curl you may need to set the mime type.
With some file types, curl will upload the file as application/octet-stream. You can pass a custom mime type like this: -F "file=#file.wav;type=audio/wav" "
I was trying -F "image=#file.wav;type=audio/wav" when translated from Alamofire. It needs to be: -F "file=#file.wav;type=audio/wav"

Related

HOW TO POST IMAGE FILE WITH ALAMOFIRE 5.5

i want to POST an image file with multipartform using alamofire 5.5
im success to implement the GET method with this recently alamofire but get stuck with the POST method.
TIA
For Uploading images to server we need to use multipart request, you can upload the image to a server by using the following code snippet.
func uploadImage(imgType:String,imgData:Data,imageName:String){
// params to send additional data, for eg. AccessToken or userUserId
let params = ["userID":"userId","accessToken":"your accessToken"]
print(params)
AF.upload(multipartFormData: { multiPart in
for (key,keyValue) in params{
if let keyData = keyValue.data(using: .utf8){
multiPart.append(keyData, withName: key)
}
}
multiPart.append(imgData, withName: "key",fileName: imageName,mimeType: "image/*")
}, to: "Your URL",headers: []).responseJSON { apiResponse in
switch apiResponse.result{
case .success(_):
let apiDictionary = apiResponse.value as? [String:Any]
print("apiResponse --- \(apiDictionary)")
case .failure(_):
print("got an error")
}
}
}

How to upload multipart form data inside a dictionary?

I am trying to upload a video to my rails API backend using Swift. To upload this I use Alamofire. The only problem is that the rails api is expecting this: {"video":{"clip": (form data)}}. The problem that I am having is storing the multipart form data is that it doesn't seem I can store it inside the second dictionary. I have tried params for my video, but it doesn't seem to work. Here is some of my code if it helps:
The Alamofire Request
AF.upload(
multipartFormData: { multipartFormData in
for (_, _) in params {
multipartFormData.append(self.videoURL, withName: "clip" , fileName: "clip.mp4", mimeType: "video/mp4")
}
multipartFormData.append("\(Id)".data(using: String.Encoding.utf8, allowLossyConversion: false)!, withName :"Id")
},
to: "http://10.0.0.2:3000/api/v1/videouploads.json", method: .post, headers: headers)
.response { resp in
print(resp)
}
What the server expects (pretty printed)
{
"video": {
"clip": (multipartformdata)
}
"id": (user id)
}
Try this:
multipartFormData.append(
self.videoURL,
withName: "video[clip]", // this is location in form' struct
fileName: "clip.mp4",
mimeType: "video/mp4"
)

Log alamofire upload image request and response

I know there is a lot about this issue but I can't find exactly the one related to uploading. I'm using alamofire for my HTTP calls.
I'm trying to upload the image to Amazon S3 and getting an error, wanting to log request and response to see what exactly problem is.
All my requests are logging except Alamofire.upload. I added an extension to request and Aramofire.request is logging and now my problem is to log also Alamofire.upload.
As an example, I'm trying to log request and response for the following example.
Alamofire.upload(multipartFormData: { (multipartFormData) in
for (key, value) in params {
multipartFormData.append(value.data(using: String.Encoding.utf8, allowLossyConversion: false)!, withName: key)
}
if image != nil {
if let imgData = UIImageJPEGRepresentation(image!, 0.8) {
multipartFormData.append(imgData, withName: "file", fileName: "file.jpg", mimeType: "image/jpeg")
}
}
}, to: "amazon.s3.URL")
After digging into SessionManager class I found out the way how to log upload request and response.
I override the upload function.
Here is my example
class AlamofireManager: SessionManager {
override func upload(_ data: Data, with urlRequest: URLRequestConvertible) -> UploadRequest {
let request = super.upload(data, with: urlRequest)
print("Request: \(request.debugDescription)")
print("Response: \(request.response.data)")
return request
}
}
You can also use this pod https://github.com/konkab/AlamofireNetworkActivityLogger and you can call it in applicationDidLaunch.. it will log everything pretty nice.

Alamofire photo upload with key of the file in body

I am able to upload a photo via Postman but in my iOS application it fails, and it is so weird that I still get a .success from encodingCompletion.
Here is part of my code
UpdateUserInfo
//
// Update user info
//
func updateUserInfo(){
var imageData: Data!
var url = ""
if let userId = KeychainWrapper.standard.string(forKey: USER_ID_KEY){
url = URL_USER_UPLOAD_PIC + userId
}
if pickedImage != nil{
imageData = UIImagePNGRepresentation(pickedImage)
//imageData = UIImageJPEGRepresentation(pickedImage!, 1.0)
}
let token = KeychainWrapper.standard.string(forKey: USER_LOGIN_TOKEN_KEY)!
let headers: HTTPHeaders = [
"Authorization": "Bearer \(token)"
]
if imageData != nil{
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(imageData!, withName: "fileset", fileName: "file.png", mimeType: "image/png")
}, to: url,
method: .post,
headers: headers,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
print("Donkey Success \(String(describing: upload.response?.statusCode))")
upload.responseString(completionHandler: { (response) in
debugPrint(response)
})
case .failure(let encodingError):
print(encodingError)
print("Donkey Fail")
}
})
}
}
and in my postman I have
Postman
My first question is why I am getting a .success if it fails to upload?
and my second question is, do I need to put the key "pic" (seen in Postman) somewhere in my request? if so where?
Thanks for any help in advance
In Post man Image Key is pic but in your code its "fileset"
change to
multipartFormData.append(imageData!, withName: "pic", fileName: "file.png", mimeType: "image/png")
And success is Result of encoding not uploading processs
EncodingResult is MultipartFormDataEncodingResult that Defines
whether the MultipartFormData encoding was successful and contains
result of the encoding as associated values. - Success: Represents a successful MultipartFormData encoding and contains the
new UploadRequest along with
streaming information. - Failure: Used to represent a failure in the MultipartFormData encoding and also
contains the encoding

Swift Alamofire upload image in variable for rails API

So here is my problem, I must upload an image in my swift application to a server that use rails. I got almost everything set up, except that the rails api must receive the file data in a variable document[:file]
here is the function I use to encode my image with alamofire:
static func getDocumentCreateUploadData(parameters: [String : AnyObject], imageData: NSData) -> (uploadData:NSMutableData, contentType:String) {
let boundaryConstant = "NET-POST-boundary-\(arc4random())-\(arc4random())";
let contentType = "multipart/form-data;boundary="+boundaryConstant
let uploadData = NSMutableData()
// add image
uploadData.appendData("\r\n--\(boundaryConstant)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("Content-Disposition: form-data; name=\"file\"; filename=\"file.png\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("Content-Type: image/png\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData(imageData)
// add parameters
for (key, value) in parameters {
uploadData.appendData("\r\n--\(boundaryConstant)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n\(value)".dataUsingEncoding(NSUTF8StringEncoding)!)
}
uploadData.appendData("\r\n--\(boundaryConstant)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
return (uploadData, contentType)
}
And then I call my api with
var imageParameters = [
"documents": [
"documentable_type": "Profile",
"documentable_id": user.profile.id!
]
]
let data = Router.getDocumentCreateUploadData(imageParameters, imageData: imageData)
let urlRequest = Router.CreateDocument(contentType: data.contentType)
Alamofire.upload(urlRequest, data.uploadData).validate().responseSwiftyJSON({ (request, response, json, error) in
if error != nil {
...
What I would like to know is how can I encode the image so that it respect the api specification.
{
"documents" : {
"file": the_file,
"documentable_type": the_documentable_type,
"documentable_id": the_documentable_id
}
}
Is there a way to achieve this?
Thank in advance.
I simply misundertood the api, I didn't needed the root document in my upload call
All I needed to do was remove the document root but here is the way I did it :
let imageParameters = [
"documentable_type": "Comment",
"organization_id": organizationId,
"member_id": memberId,
"user_id": user.id
]
let uuid = NSUUID().UUIDString
composeBarView.enabled = false
ProgressHUDManager.uploadingStatus()
Alamofire.upload(
Router.CreateDocument,
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(data: imageData!, name: "file", fileName: "\(uuid).jpg", mimeType: "image/jpeg")
for (key, value) in imageParameters {
multipartFormData.appendBodyPart(data: value.dataUsingEncoding(NSUTF8StringEncoding)!, name: key)
}
},
encodingCompletion: { encodingResult in
// Handle result
}
)
The API Evolved so the code is new but I hope it can help