Related
Hello I am trying to post a parameter and/or image.
My parameter is a [String : Any] with string, date, int, values.
When I post only a parameter I use URLEncoding.default encoding. However when I need to post both parameter and image I use multipartFormData.
My code is below
if url == ""{
AF.upload(multipartFormData: { multipartFormData in
for (key,value) in parameters {
multipartFormData.append((value as! String).data(using: .utf8)!, withName: key)
}
let jpegData = art!.jpegData(compressionQuality: 1.0)
multipartFormData.append(Data((jpegData)!), withName: "photo")
}, to: "\(NetworkManager.rootURL)/api/add/")
.responseJSON { response in
debugPrint(response)
}
}else{
AF.request("\(NetworkManager.rootURL)/api/add/", method: .post, parameters: parameters, encoding: URLEncoding.default, headers: nil).response { (reponse) in
let status = reponse.response!.statusCode
if status == 200{
completion(200)
}else{
completion(401)
}
}
}
My problem is that because my parameter is a any with string date int values I get a
Could not cast value of type 'Swift.Int' (0x1c3f1f1e8) to 'Swift.String' (0x1c3f21390). Is there any workaround for this? or do I have to change everything to string...
Any help is appreciated
You need to path any value as a String for this to work as it's the only way to transfer it to Data , some others use
for (key, value) in parameters {
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
I have maked block function for Upload image with parameter to Server Using Multipart
//Here strUrl = YOUR WEBSERVICE URL
//postParam = post Request parameter i.e.
//let postParam : [String : Any] = [first_name : "name"]
//imageArray = image upload array i.e.
//var imageArray : [[String:Data]] = [["image_name" : YOUR IMAGE DATA]]
func postImageRequestWithURL(withUrl strURL: String,withParam postParam: Dictionary<String, Any>,withImages imageArray:[[String:Data]], completion:#escaping (_ isSuccess: Bool, _ response:NSDictionary) -> Void)
{
let requetURL = strURL
Alamofire.upload(multipartFormData: { (MultipartFormData) in
for (imageDic) in imageArray
{
for (key,value) in imageDic
{
MultipartFormData.append(value, withName:key,fileName: "file.jpg", mimeType: "image/jpg")
}
}
for (key, value) in postParam
{
MultipartFormData.append("\(value)".data(using: .utf8)!, withName: key)
// MultipartFormData.append(value, withName: key)
}
}, usingThreshold: UInt64.init(), to: requetURL, method: .post, headers: ["Accept": "application/json"]) { (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print("Upload Progress: \(progress.fractionCompleted)")
})
upload.responseJSON { response in
let desiredString = NSString(data: response.data!, encoding: String.Encoding.utf8.rawValue)
print("Response ====================")
print(desiredString!)
if let json = response.result.value as? NSDictionary
{
if response.response?.statusCode == 200
|| response.response?.statusCode == 201
|| response.response?.statusCode == 202
{
completion(true,json);
}
else
{
completion(false,json);
}
}
else
{
completion(false,[:]);
}
}
case .failure(let encodingError):
print(encodingError)
completion(false,[:]);
}
}
}
You can also upload multiple image using this
I Hope this will help...
I am trying upload files with parameters (multipartformdata) but i can't do it with new version Alamofire 5, if you have some experience with Alamofire 5 please share it with me.
func uploadPluckImage(imgData : Data, imageColumnName : String, url:String,httpmethod:HTTPMethod,completionHandler: #escaping (NSDictionary?, String?) -> ()){
let token = UserDefaults.standard.string(forKey: PrefKeys.loginToken) ?? ""
let authorization = ["Authorization" : "Bearer \(token)"]
let parameters: Parameters?
parameters = [
"garbageCollector": 0,
"stuff_uuid": "2b4b750a-f4a6-4d61-84ce-7c42b5c030ee",
"delete_file" : ""
]
let headers : HTTPHeader?
headers = ["Authorization" : "Bearer \(token)"]
let imageURl = "http://68.183.152.132/api/v1/stuff/uploader"
AF.upload(multipartFormData: { (multipart: MultipartFormData) in
let imageData = self.firstImage.image?.jpegData(compressionQuality: 0.7)
multipart.append(imageData, withName: "file", fileName: "file.png", mimeType: "image/png")
for (key, value) in parameters!{
multipart.append(value as! String).data(using: .utf8)!, withName: key)
}
},usingThreshold: UInt64.init(),
to: imageURl,
method: .post,
headers: headers,
encodingCompletion: { (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print("Uploading")
})
break
case .failure(let encodingError):
print("err is \(encodingError)")
break
}
})
}
Upload method slightly changed in Alamofire 5
func upload(image: Data, to url: Alamofire.URLRequestConvertible, params: [String: Any]) {
AF.upload(multipartFormData: { multiPart in
for (key, value) in params {
if let temp = value as? String {
multiPart.append(temp.data(using: .utf8)!, withName: key)
}
if let temp = value as? Int {
multiPart.append("\(temp)".data(using: .utf8)!, withName: key)
}
if let temp = value as? NSArray {
temp.forEach({ element in
let keyObj = key + "[]"
if let string = element as? String {
multiPart.append(string.data(using: .utf8)!, withName: keyObj)
} else
if let num = element as? Int {
let value = "\(num)"
multiPart.append(value.data(using: .utf8)!, withName: keyObj)
}
})
}
}
multiPart.append(image, withName: "file", fileName: "file.png", mimeType: "image/png")
}, with: url)
.uploadProgress(queue: .main, closure: { progress in
//Current upload progress of file
print("Upload Progress: \(progress.fractionCompleted)")
})
.responseJSON(completionHandler: { data in
//Do what ever you want to do with response
})
}
Hope this will help you
EDIT: In case you don't quite get the above, here is an expansion:
let uploadRequest: UploadRequest = AF.upload(multipartFormData: multipartFormData, with: ...)
let completionHander: (AFDataResponse<Any>) -> Void) = { result in
//Do what ever you want to do with response, which is a DataResponse<Success, AFError>
}
// Adds that completion hander to the UploadRequest
uploadRequest.responseJSON(completionHandler: completionHander)
This how I upload images and videos from a swift 5 app with Alamofire 5.
Images
/**
Send Image to server
*/
func Post(imageOrVideo : UIImage?){
let headers: HTTPHeaders = [
/* "Authorization": "your_access_token", in case you need authorization header */
"Content-type": "multipart/form-data"
]
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(imageOrVideo!.jpegData(compressionQuality: 0.5)!, withName: "upload_data" , fileName: "file.jpeg", mimeType: "image/jpeg")
},
to: "http://ip.here.--.--/new.php", method: .post , headers: headers)
.response { resp in
print(resp)
}
}
You can create a temporary resource and use the temporary url (good for videos):
/**
Send video to server
*/
func PostVideoUrl(url : URL){
let headers: HTTPHeaders = [
"Content-type": "multipart/form-data"
]
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(url, withName: "upload_data" , fileName: "movie.mp4", mimeType: "video/mp4")
},
to: "http://ip.here.--.--/newVideo.php", method: .post , headers: headers)
.response { resp in
print(resp)
}
}
This Is work for me Using Swift 4.2 Please try this
let url = "http://google.com" /* your API url */
let headers: HTTPHeaders = [
/* "Authorization": "your_access_token", in case you need authorization header */
"Content-type": "multipart/form-data"
]
Alamofire.upload(multipartFormData: { (multipartFormData) in
for (key, value) in parameters {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
if let data = imageData{
multipartFormData.append(data, withName: "image", fileName: "image.png", mimeType: "image/png")
}
}, usingThreshold: UInt64.init(), to: url, method: .post, headers: headers) { (result) in
switch result{
case .success(let upload, _, _):
upload.responseJSON { response in
print("Succesfully uploaded")
if let err = response.error{
onError?(err)
return
}
onCompletion?(nil)
}
case .failure(let error):
print("Error in upload: \(error.localizedDescription)")
onError?(error)
}
}
func upload(image: Data, to url: URL, params: [String: Any]) {
let block = { (multipart: MultipartFormData) in
URLEncoding.default.queryParameters(params).forEach { (key, value) in
if let data = value.data(using: .utf8) {
multipart.append(data, withName: key)
}
}
multiPart.append(image, withName: "file", fileName: "file.png", mimeType: "image/png")
}
AF.upload(multipartFormData: block, to: url)
.uploadProgress(queue: .main, closure: { progress in
//Current upload progress of file
print("Upload Progress: \(progress.fractionCompleted)")
})
.responseJSON(completionHandler: { data in
//Do what ever you want to do with response
})
}
extension URLEncoding {
public func queryParameters(_ parameters: [String: Any]) -> [(String, String)] {
var components: [(String, String)] = []
for key in parameters.keys.sorted(by: <) {
let value = parameters[key]!
components += queryComponents(fromKey: key, value: value)
}
return components
}
}
Upload two images with parameters with Headers , Using Alamofire 5
i solve this issue try this code ..
//MARK: Upload Images with Params API's
func upload(icon: Data, image : Data, params: [String: Any]) {
let urlString = "Your URL String "
let headers: HTTPHeaders =
["Content-type": "multipart/form-data",
"Accept": "application/json"]
AF.upload(
multipartFormData: { multipartFormData in
for (key, value) in params {
if let temp = value as? String {
multipartFormData.append(temp.data(using: .utf8)!, withName: key)}
if let temp = value as? Int {
multipartFormData.append("(temp)".data(using: .utf8)!, withName: key)}
if let temp = value as? NSArray {
temp.forEach({ element in
let keyObj = key + "[]"
if let string = element as? String {
multipartFormData.append(string.data(using: .utf8)!, withName: keyObj)
} else
if let num = element as? Int {
let value = "(num)"
multipartFormData.append(value.data(using: .utf8)!, withName: keyObj)
}
})
}
}
multipartFormData.append(icon, withName: "icon", fileName: "icon.png", mimeType: "icon/png")
multipartFormData.append(image, withName: "registerImage", fileName: "registerImage.png", mimeType: "registerImage/png")
},
to: urlString, //URL Here
method: .post,
headers: headers)
.responseJSON { (resp) in
defer{SVProgressHUD.dismiss()}
print("resp is \(resp)")
}
}##
Heading
#
You can do that using Router URLRequestConvertible
static func performMultiPartFile<T:Decodable>(imageData: Data, route:APIRoute,decoder: JSONDecoder = JSONDecoder(), completion: #escaping (_ result: T?, _ error: String?) -> ()) {
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(imageData, withName: "image", fileName: "iosImage.jpg", mimeType: "image/jpg")
}, with: route) { (encodingResult) in
switch encodingResult {
case .success(let upload, _, _):
upload.responseString { (response) in
if response.result.isSuccess {
if let JSON = response.result.value {
debugPrint("✅ Respons Object >>>> " + String(describing: JSON))
do {
let result = try JSONDecoder().decode(T.self, from: JSON.data(using: .utf8)!)
debugPrint("✍️ Result: " + String(describing: result))
completion(result, nil)
} catch let error { // mapping fail
debugPrint("❌ Error in Mapping" + String(describing: error))
completion(nil, String(describing: error))
}
}
} else {
debugPrint("❌ 😝 Response fail : \(response.result.description)")
completion(nil, (response.result.error?.localizedDescription)!)
}
}
case .failure(let encodingError):
completion(nil, String(describing: encodingError))
}
}
}
This is work with params.
func uploadImage(isUser:Bool, endUrl: String, imageData: Data?, parameters: [String : Any], onCompletion: ((_ isSuccess:Bool) -> Void)? = nil, onError: ((Error?) -> Void)? = nil){
headers = [
"Accept": "application/json",
"Content-type": "multipart/form-data"
]
AF.upload(multipartFormData: { multipartFormData in
for (key, value) in parameters {
if let temp = value as? String {
multipartFormData.append(temp.data(using: .utf8)!, withName: key)
}
if let temp = value as? Int {
multipartFormData.append("\(temp)".data(using: .utf8)!, withName: key)
}
if let temp = value as? NSArray {
temp.forEach({ element in
let keyObj = key + "[]"
if let string = element as? String {
multipartFormData.append(string.data(using: .utf8)!, withName: keyObj)
} else
if let num = element as? Int {
let value = "\(num)"
multipartFormData.append(value.data(using: .utf8)!, withName: keyObj)
}
})
}
}
if let data = imageData{
multipartFormData.append(data, withName: "file", fileName: "\(Date.init().timeIntervalSince1970).png", mimeType: "image/png")
}
},
to: endUrl, method: .post , headers: headers)
.responseJSON(completionHandler: { (response) in
print(response)
if let err = response.error{
print(err)
onError?(err)
return
}
print("Succesfully uploaded")
let json = response.data
if (json != nil)
{
let jsonObject = JSON(json!)
print(jsonObject)
}
})
}
I am using Alamofire for uploading image and file to the server. But I am facing issue to send an array in parameters with the image. But when I send an array in params it converts the array in JSON string. But I want to send an array in params, not JSON string. I have searched a lot and did not find any solution. So please tell me what's wrong in my code. I am using below code:
let params = ["id":"112","arrayParam":["1232","12344","14325"]]
let url = www.khxjjhdfsj.com/hsdgs
let headers: HTTPHeaders = [
/* "Authorization": "your_access_token", in case you need authorization header */
"Content-type": "multipart/form-data"
]
Alamofire.upload(multipartFormData: { (multipartFormData) in
for (key, value) in params
{
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
if let data = imageData
{
multipartFormData.append(data, withName: "file", fileName: fileName, mimeType: "image/png")
}
if let data = pdfData
{
multipartFormData.append(data, withName: "file", fileName: fileName, mimeType:"application/pdf")
}
}, usingThreshold: UInt64.init(), to: url, method: .post, headers: headers) { (result) in
switch result{
case .success(let upload, _, _):
upload.responseJSON { response in
print("Succesfully uploaded")
if let err = response.error
{
onError?(err)
return
}
}
case .failure(let error):
print("Error in upload: \(error.localizedDescription)")
onError?(error)
}
}
You need to pass image parameter along with your other request parameters. Pass your array parameters like this in below code:
Alamofire.upload(
multipartFormData: { multipartFormData in
// Pass your image parameter in imgObj
if let imageData = UIImageJPEGRepresentation(imgObj, 1) {
multipartFormData.append(UIImagePNGRepresentation(imgObj)!, withName: "profile_image", fileName: "THDC", mimeType: "image/png")
}
// Send other request parameters
for (key, value) in yourArray {
multipartFormData.append((value as! String).data(using: .utf8)!, withName: key)
}
},to: YourURL,headers:[:],
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
SVProgressHUD.dismiss()
debugPrint("SUCCESS RESPONSE: \(response)")
if let dicObj = response.result.value as? NSDictionary {
print(dicObj)
}
}
case .failure(let encodingError):
SVProgressHUD.dismiss()
print("ERROR RESPONSE: \(encodingError)")
}
}
)
This is the static way to upload arrays to Alamofire.
hope this may useful to you.
Alamofire.upload(multipartFormData: { (multipartFormData) in
let imageData = UIImageJPEGRepresentation(imageUpload!, 0.5)
multipartFormData.append(imageData!, withName: "profile_file", fileName: "file.png", mimeType: "image/jpg")
for (key, value) in parameters {
if (value as AnyObject).isKind(of: NSMutableArray.self)
{
let arrayObj = value as! NSMutableArray
//let data2 = NSData(bytes: &arrayObj, length: arrayObj.count)
let count : Int = arrayObj.count
for i in 0 ..< count
{
let value = arrayObj[i] as! Int
let valueObj = String(value)
let keyObj = key + "[" + String(i) + "]"
multipartFormData.append(valueObj.data(using: String.Encoding.utf8)!, withName: keyObj)
}
}
else{
var valueStr = String()
if let param = value as? String{
valueStr = param
}else{
let valueInt = value as! Int
valueStr = String(valueInt)
}
multipartFormData.append((valueStr).data(using: String.Encoding.utf8)!, withName: key)
}
}
}, to: urlString, encodingCompletion: { (encodingResult) in
print("=====encodingResult=========",encodingResult)
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON(completionHandler: { (response) -> Void in
switch response.result {
case .success(let JSON):
print("JSON: \(JSON)")
onCompletion(JSON as? NSDictionary, nil)
case .failure(let error):
print(error)
}
})
case .failure(let encodingError):
print(encodingError);
}
})
You need to append array with multipart data on the same key required, like in your code you need to change only given line of code:
for (key, value) in params
{
// check the key on which key array is coming
if key == "arrayParam" {
let arrData = try! JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
multipartFormData.append(arrData, withName: key as String)
}
else {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
}
Rest will be the same.
I am uploading image with multipart form data using Alamofire but getting some problem while i am passing an array as parameter.
As per request i need to pass all data into letter.
Here is how i am doing.
let data = try! JSONSerialization.data(withJSONObject: arrSelectedRecipientsID, options: .prettyPrinted)
let jsonString = String(data: data, encoding: .utf8)!
let paramArr : [String : Any] = [
"message" : txtvwMessage.text!,
"status": "draft",
"recipient_ids": jsonString
]
let parameter : [String : Any] = ["letter" : paramArr]
let accesstoken = Utilities.retriveValueFromDefault(forKey: UDKey.kUserAuthentication_Token) as String
let client = Utilities.retriveValueFromDefault(forKey: UDKey.kUserClient) as String
let uid = Utilities.retriveValueFromDefault(forKey: UDKey.kUserUID) as String
let headersInfo : HTTPHeaders = [ "Content-Type" : "multipart/form-data",
"Accept" : "application/json",
"access-token" : accesstoken,
"client" : client,
"uid" : uid
]
fileUploadWithParameter(Constant.ServerAPI.kPostLetters, images: letterImage, header: headersInfo, parameters: parameter, success: { (response) in
print(response)
}) { (progress) in
}
Here is Alamofire request method.
func fileUploadWithParameter(_ url: String,images:NSMutableArray,header : [String : String], parameters: [String:Any], success:#escaping (NSDictionary)->(),progressHandler:#escaping(_ progress: Double)->Void) {
Alamofire.upload(multipartFormData: { multipartFormData in
for i in 0..<images.count {
let rotatedImage = images[i] as! UIImage
if let imgData = UIImageJPEGRepresentation(rotatedImage, 0.8) {
multipartFormData.append(imgData, withName: "letter[photos]",fileName: "0\(i).jpg", mimeType: "image/jpg")
}
}
for (key, value) in parameters {
//multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key )
let paramsData:Data = NSKeyedArchiver.archivedData(withRootObject: value)
multipartFormData.append(paramsData, withName: key)
}
}, to: url,
method:.post,
headers:header) { (result) in
print("\n\n\nRequest URL :- \(url)\nParameters :- \(parameters)")
switch result {
case .success(let upload, _, _):
upload.responseJSON { response in
if response.error != nil {
print("Error :- \((response.error?.localizedDescription)!)\n\n\n")
}
if let jsonDict = response.result.value as? NSDictionary {
print("Response :- \(jsonDict)\n\n\n")
} else {
print("Error :- \(Constant.ErrorMessage.kCommanError)\n\n\n")
}
}
case .failure(let encodingError):
print("Error :- \(encodingError.localizedDescription)\n\n\n")
}
}
}
Postman works well so can someone please help me where i am doing wrong.
API expected The proper json should be
{
"letter":
{
"message": "Type your message here...!!!",
"recipient_ids": [183, 184],
"status": "draft"
}
}
API is in ruby on rails and it says i am sending string. Please help me to find out what is issue.
Jus need to change only given line of code:
for (key, value) in parameters {
if key == "letter" {
let arrData = try! JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
multipartFormData.append(arrData, withName: key as String)
}
else {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
}
Rest will be the same.
your method in updated form:
func fileUploadWithParameter(_ url: String,images:NSMutableArray,header : [String : String], parameters: [String:Any], success:#escaping (NSDictionary)->(),progressHandler:#escaping(_ progress: Double)->Void) {
Alamofire.upload(multipartFormData: { multipartFormData in
for i in 0..<images.count {
let rotatedImage = images[i] as! UIImage
if let imgData = UIImageJPEGRepresentation(rotatedImage, 0.8) {
multipartFormData.append(imgData, withName: "letter[photos]",fileName: "0\(i).jpg", mimeType: "image/jpg")
}
}
for (key, value) in parameters {
//multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key )
let paramsData:Data = NSKeyedArchiver.archivedData(withRootObject: value)
multipartFormData.append(paramsData, withName: key)
}
for (key, value) in parameters {
if key == "letter" {
let arrData = try! JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
multipartFormData.append(arrData, withName: key as String)
}
else {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
}
}, to: url,
method:.post,
headers:header) { (result) in
print("\n\n\nRequest URL :- \(url)\nParameters :- \(parameters)")
switch result {
case .success(let upload, _, _):
upload.responseJSON { response in
if response.error != nil {
print("Error :- \((response.error?.localizedDescription)!)\n\n\n")
}
if let jsonDict = response.result.value as? NSDictionary {
print("Response :- \(jsonDict)\n\n\n")
} else {
//print("Error :- \(Constant.ErrorMessage.kCommanError)\n\n\n")
print("Errfdc")
}
}
case .failure(let encodingError):
print("Error :- \(encodingError.localizedDescription)\n\n\n")
}
}
}
Finally get it done with separate append in request. Here is how you can pass an array in multipart form data request.
Alamofire.upload(multipartFormData: { multipartFormData in
for i in 0..<self.letterImage.count {
let rotatedImage = self.letterImage[i] as! UIImage
if let imgData = UIImageJPEGRepresentation(rotatedImage, 0.8) {
multipartFormData.append(imgData, withName: "letter[photos][]",fileName: "0\(i).jpg", mimeType: "image/jpg")
}
}
multipartFormData.append("\(message)".data(using: String.Encoding.utf8)!, withName: "letter[message]")
multipartFormData.append("draft".data(using: String.Encoding.utf8)!, withName: "letter[status]")
for (_,value) in self.arrSelectedRecipientsID.enumerated() {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: "letter[recipient_ids][]")
}
}
you can append array of like below
for image attachments
for Attachment in Attachments
{
if let pic = Attachment{
let randome = arc4random()
let data = UIImageJPEGRepresentation(pic, 0.8)
MultipartFormData.append(data!, withName: "letter[photos][]", fileName: "randome\(randome).jpg", mimeType: "image/jpg")
}
}
for parameters
for (key,value) in params
{
MultipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: "\(key)")
}
I am using Alamofire, very first time. I am using the latest version Alamofire 1.3.1. I want to send one image , one video and some POST parameters in one API call. I am using multipart form data. The mutipart module is working. I am facing a problem to send extra POST parametersparams . Below is my code. "params" is the dictionary which contains extra parameters? How can I append these POST parameters in the request. Please help
var fullUrl :String = Constants.BASE_URL + "/api/CompleteChallenge"
var params = [
"authKey": Constants.AuthKey,
"idUserChallenge": "16",
"comment": "",
"photo": imagePath,
"video": videoPath,
"latitude": "1",
"longitude": "1",
"location": "india"
]
let imagePathUrl = NSURL(fileURLWithPath: imagePath!)
let videoPathUrl = NSURL(fileURLWithPath: videoPath!)
Alamofire.upload(
.POST,
URLString: fullUrl, // http://httpbin.org/post
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(fileURL: imagePathUrl!, name: "photo")
multipartFormData.appendBodyPart(fileURL: videoPathUrl!, name: "video")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { request, response, JSON, error in
}
}
case .Failure(let encodingError):
}
}
)
I found the solution :) finally.
We can append data in the request as multipartformdata.
Below is my code.
Alamofire.upload(
.POST,
URLString: fullUrl, // http://httpbin.org/post
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(fileURL: imagePathUrl!, name: "photo")
multipartFormData.appendBodyPart(fileURL: videoPathUrl!, name: "video")
multipartFormData.appendBodyPart(data: Constants.AuthKey.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"authKey")
multipartFormData.appendBodyPart(data: "\(16)".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"idUserChallenge")
multipartFormData.appendBodyPart(data: "comment".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"comment")
multipartFormData.appendBodyPart(data:"\(0.00)".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"latitude")
multipartFormData.appendBodyPart(data:"\(0.00)".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"longitude")
multipartFormData.appendBodyPart(data:"India".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"location")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { request, response, JSON, error in
}
case .Failure(let encodingError):
}
}
)
EDIT 1: For those who are trying to send an array instead of float, int or string, They can convert their array or any kind of data-structure in Json String, pass this JSON string as a normal string. And parse this json string at backend to get original array
In Alamofire 4 it is important to add the body data before you add the file data!
let parameters = [String: String]()
[...]
self.manager.upload(
multipartFormData: { multipartFormData in
for (key, value) in parameters {
multipartFormData.append(value.data(using: .utf8)!, withName: key)
}
multipartFormData.append(imageData, withName: "user", fileName: "user.jpg", mimeType: "image/jpeg")
},
to: path,
[...]
)
This is how i solve my problem
let parameters = [
"station_id" : "1000",
"title": "Murat Akdeniz",
"body": "xxxxxx"]
let imgData = UIImageJPEGRepresentation(UIImage(named: "1.png")!,1)
Alamofire.upload(
multipartFormData: { MultipartFormData in
// multipartFormData.append(imageData, withName: "user", fileName: "user.jpg", mimeType: "image/jpeg")
for (key, value) in parameters {
MultipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
}
MultipartFormData.append(UIImageJPEGRepresentation(UIImage(named: "1.png")!, 1)!, withName: "photos[1]", fileName: "swift_file.jpeg", mimeType: "image/jpeg")
MultipartFormData.append(UIImageJPEGRepresentation(UIImage(named: "1.png")!, 1)!, withName: "photos[2]", fileName: "swift_file.jpeg", mimeType: "image/jpeg")
}, to: "http://platform.twitone.com/station/add-feedback") { (result) in
switch result {
case .success(let upload, _, _):
upload.responseJSON { response in
print(response.result.value)
}
case .failure(let encodingError): break
print(encodingError)
}
}
Swift 3 / Alamofire 4.0 (Addendum to the accepted answer)
To append to multipartFormData in Swift 3 / Alamofire 4.0, use the following method of MultipartFormData:
public func append(_ data: Data, withName name: String) { /* ... */ }
And, to convert String to Data, the data(using:) method of String. E.g.,
multipartFormData.append("comment".data(using: .utf8)!, withName: "comment")
For Swift 4.2 / Alamofire 4.7.3
Alamofire.upload(multipartFormData: { multipart in
multipart.append(fileData, withName: "payload", fileName: "someFile.jpg", mimeType: "image/jpeg")
multipart.append("comment".data(using: .utf8)!, withName :"comment")
}, to: "endPointURL", method: .post, headers: nil) { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.response { answer in
print("statusCode: \(answer.response?.statusCode)")
}
upload.uploadProgress { progress in
//call progress callback here if you need it
}
case .failure(let encodingError):
print("multipart upload encodingError: \(encodingError)")
}
}
Also you could take a look at CodyFire lib it makes API calls easier using Codable for everything.
Example for Multipart call using CodyFire
//Declare your multipart payload model
struct MyPayload: MultipartPayload {
var attachment: Attachment //or you could use just Data instead
var comment: String
}
// Prepare payload for request
let imageAttachment = Attachment(data: UIImage(named: "cat")!.jpeg(.high)!,
fileName: "cat.jpg",
mimeType: .jpg)
let payload = MyPayload(attachment: imageAttachment, comment: "Some text")
//Send request easily
APIRequest("endpoint", payload: payload)
.method(.post)
.desiredStatus(.created) //201 CREATED
.onError { error in
switch error.code {
case .notFound: print("Not found")
default: print("Another error: " + error.description)
}
}.onSuccess { result in
print("here is your decoded result")
}
//Btw normally it should be wrapped into an extension
//so it should look even easier API.some.upload(payload).onError{}.onSuccess{}
You could take a look at all the examples in lib's readme
Alamofire 5 and above
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(Data("one".utf8), withName: "one")
multipartFormData.append(Data("two".utf8), withName: "two")
},
to: "https://httpbin.org/post").responseDecodable(of: MultipartResponse.self) { response in
debugPrint(response)
}
documentation link: multipart upload
Swift 5, update #Ankush's Alamofire Code to
var fullUrl = "http://httpbin.org/post" // for example
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append( imagePathUrl! , withName: "photo")
multipartFormData.append( videoPathUrl!, withName: "video")
multipartFormData.append(Constants.AuthKey.data(using: .utf8, allowLossyConversion: false)!, withName: "authKey")
multipartFormData.append("16".data(using: .utf8, allowLossyConversion: false)!, withName: "idUserChallenge")
multipartFormData.append("111".data(using: .utf8, allowLossyConversion: false)!, withName: "authKey")
multipartFormData.append("comment".data(using: .utf8, allowLossyConversion: false)!, withName: "comment")
multipartFormData.append("0.00".data(using: .utf8, allowLossyConversion: false)!, withName: "latitude")
multipartFormData.append("0.00".data(using: .utf8, allowLossyConversion: false)!, withName: "longitude")
multipartFormData.append("India".data(using: .utf8, allowLossyConversion: false)!, withName: "location")
}, to: fullUrl, method: .post) { (encodingResult) in
switch encodingResult {
case .success(request: let upload, streamingFromDisk: _, streamFileURL: _):
upload.responseJSON { (response) in // do sth }
case .failure(let encodingError):
()
}
}
As in Swift 3.x for upload image with parameter we can use below alamofire upload method-
static func uploadImageData(inputUrl:String,parameters:[String:Any],imageName: String,imageFile : UIImage,completion:#escaping(_:Any)->Void) {
let imageData = UIImageJPEGRepresentation(imageFile , 0.5)
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(imageData!, withName: imageName, fileName: "swift_file\(arc4random_uniform(100)).jpeg", mimeType: "image/jpeg")
for key in parameters.keys{
let name = String(key)
if let val = parameters[name!] as? String{
multipartFormData.append(val.data(using: .utf8)!, withName: name!)
}
}
}, to:inputUrl)
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (Progress) in
})
upload.responseJSON { response in
if let JSON = response.result.value {
completion(JSON)
}else{
completion(nilValue)
}
}
case .failure(let encodingError):
completion(nilValue)
}
}
}
Note: Additionally if our parameter is array of key-pairs then we can
use
var arrayOfKeyPairs = [[String:Any]]()
let json = try? JSONSerialization.data(withJSONObject: arrayOfKeyPairs, options: [.prettyPrinted])
let jsonPresentation = String(data: json!, encoding: .utf8)
Well, since Multipart Form Data is intended to be used for binary ( and not for text) data transmission, I believe it's bad practice to send data in encoded to String over it.
Another disadvantage is impossibility to send more complex parameters like JSON.
That said, a better option would be to send all data in binary form, that is as Data.
Say I need to send this data
let name = "Arthur"
let userIDs = [1,2,3]
let usedAge = 20
...alongside with user's picture:
let image = UIImage(named: "img")!
For that I would convert that text data to JSON and then to binary alongside with image:
//Convert image to binary
let data = UIImagePNGRepresentation(image)!
//Convert text data to binary
let dict: Dictionary<String, Any> = ["name": name, "userIDs": userIDs, "usedAge": usedAge]
userData = try? JSONSerialization.data(withJSONObject: dict)
And then, finally send it via Multipart Form Data request:
Alamofire.upload(multipartFormData: { (multiFoormData) in
multiFoormData.append(userData, withName: "user")
multiFoormData.append(data, withName: "picture", mimeType: "image/png")
}, to: url) { (encodingResult) in
...
}
for alamofire 4 use this ..
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(fileUrl, withName: "video")
//fileUrl is your file path in iOS device and withName is parameter name
}, to:"http://to_your_url_path")
{ (result) in
switch result {
case .success(let upload, _ , _):
upload.uploadProgress(closure: { (progress) in
print("uploding")
})
upload.responseJSON { response in
print("done")
}
case .failure(let encodingError):
print("failed")
print(encodingError)
}
}
Found one more way of doing it
if let parameters = route.parameters {
for (key, value) in parameters {
if value is String {
if let temp = value as? String {
multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
}
}
else if value is NSArray {
if let temp = value as? [Double]{
multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
}
else if let temp = value as? [Int]{
multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
}
else if let temp = value as? [String]{
multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
}
}
else if CFGetTypeID(value as CFTypeRef) == CFNumberGetTypeID() {
if let temp = value as? Int {
multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
}
}
else if CFGetTypeID(value as CFTypeRef) == CFBooleanGetTypeID(){
if let temp = value as? Bool {
multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
}
}
}
}
if let items: [MultipartData] = route.multipartData{
for item in items {
if let value = item.value{
multipartFormData.append(value, withName: item.key, fileName: item.fileName, mimeType: item.mimeType)
}
}
}
Alamofire 5 with Array params
The issue for me was that my params could be any type. Converting to them to strings and then getting the data encoding worked for most, but I kept running into issues with arrays. For arrays you have to encode each element with a key denoting its index. This is how I ended up encoding my params so it would be dynamic for any type:
let image = UIImage(named: "your image") // Change me
let imageData = image.jpegData(compressionQuality: 1.0)!
let imageKey = "image_key" // Change me
let urlString = "https://yourserver.com/yourendpoint/" // Change me
let params: [String: Any]? = [:] // Change me. Your POST params here
let headers: HTTPHeaders = [
// Change me. Your headers here.
]
AF.upload(multipartFormData: { multiPart in
for (key, value) in (params ?? [:]) {
if let arrayObj = value as? [Any] {
for index in 0..<arrayObj.count {
multiPart.append("\(arrayObj[index])".data(using: .utf8)!, withName: "\(key)[\(index)]")
}
} else {
multiPart.append("\(value)".data(using: .utf8)!, withName: key)
}
}
multiPart.append(imageData, withName: imageKey, fileName: "file.jpg", mimeType: "image/jpg")
}, to: urlString, headers: headers).responseJSON { response in
switch response.result {
case .success(_):
if let dictionary = response.value as? [String:Any] {
print("success", dictionary)
} else {
print("error")
}
case .failure(let error):
print("error", error.localizedDescription)
}
}
Also note that you have to append the image after appending all your params
func funcationname()
{
var parameters = [String:String]()
let apiToken = "Bearer \(UserDefaults.standard.string(forKey: "vAuthToken")!)"
let headers = ["Vauthtoken":apiToken]
let mobile = "\(ApiUtillity.sharedInstance.getUserData(key: "mobile"))"
parameters = ["first_name":First_name,"last_name":last_name,"email":Email,"mobile_no":mobile]
print(parameters)
ApiUtillity.sharedInstance.showSVProgressHUD(text: "Loading...")
let URL1 = ApiUtillity.sharedInstance.API(Join: "user/update_profile")
let url = URL(string: URL1.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)
var urlRequest = URLRequest(url: url!)
urlRequest.httpMethod = "POST"
urlRequest.allHTTPHeaderFields = headers
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(self.imageData_pf_pic, withName: "profile_image", fileName: "image.jpg", mimeType: "image/jpg")
for (key, value) in parameters {
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
}, with: urlRequest) { (encodingResult) in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
if let JSON = response.result.value {
print("JSON: \(JSON)")
let status = (JSON as AnyObject).value(forKey: "status") as! Int
let sts = Int(status)
if sts == 200
{
ApiUtillity.sharedInstance.dismissSVProgressHUD()
let UserData = ((JSON as AnyObject).value(forKey: "data") as! NSDictionary)
ApiUtillity.sharedInstance.setUserData(data: UserData)
}
else
{
ApiUtillity.sharedInstance.dismissSVProgressHUD()
let ErrorDic:NSDictionary = (JSON as AnyObject).value(forKey: "message") as! NSDictionary
let Errormobile_no = ErrorDic.value(forKey: "mobile_no") as? String
let Erroremail = ErrorDic.value(forKey: "email") as? String
if Errormobile_no?.count == nil
{}
else
{
ApiUtillity.sharedInstance.dismissSVProgressHUDWithError(error: Errormobile_no!)
}
if Erroremail?.count == nil
{}
else
{
ApiUtillity.sharedInstance.dismissSVProgressHUDWithError(error: Erroremail!)
}
}
}
}
case .failure(let encodingError):
ApiUtillity.sharedInstance.dismissSVProgressHUD()
print(encodingError)
}
}
}