Uploading image to server using Alamofire put request in swift iOS - ios

I have picked image from image picker and then reduced it's size to below 1 MB and then trying to upload with below function implementation but it was not successful.
Request body schema should be as mentioned in the above image.
please suggest proper way of uploading image with mentioned request body schema.
//Method for uploading image
func uploadImageFile(url:String, imageData: Data, fileName: String, completion: #escaping (Bool) -> Void) {
let headers = configureImageCurrentSession()
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(imageData, withName: fileName)
},
to: url, method: .put , headers: headers)
.response { resp in
print(resp)
print("Data::: \(String(data: resp.data ?? Data(), encoding: .utf8))")
completion(true)
}
}
According to the request body schema need to pass content as object required one how to include that as well in the request.
In completion response it prints as like this.
Data::: Optional("{"statusCode":400,"error":"Bad Request","message":"part content is missing"}")

Check this below code
func imageupload(_ url: String, _ imageData: Data,_ parameters: NSDictionary, completion: #escaping (NSDictionary) -> Void) {
//Set Your URL
guard let url = URL(string: url) else {
return
}
var urlRequest = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 10.0 * 1000)
urlRequest.httpMethod = "PUT"
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
urlRequest.addValue("your autho token", forHTTPHeaderField: "Authorization")
// Now Execute
AF.upload(multipartFormData: { multiPart in
for (key, value) in parameters {
if let temp = value as? String {
multiPart.append(temp.data(using: .utf8)!, withName: key as! String)
}
if let temp = value as? Int {
multiPart.append("\(temp)".data(using: .utf8)!, withName: key as! String)
}
if let temp = value as? NSArray {
temp.forEach({ element in
let keyObj = key as! String + "[]"
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(imageData, withName: "image", fileName: "file.png", mimeType: "image/png")
}, with: urlRequest)
.uploadProgress(queue: .main, closure: { progress in
//Current upload progress of file
print("Upload Progress: \(progress.fractionCompleted)")
})
.responseJSON(completionHandler: { data in
print("data = ",data)
switch data.result
{
case .failure(let error):
if let data = data.data {
print("Print Server Error: " + String(data: data, encoding: String.Encoding.utf8)!)
}
print(error)
case .success(let value):
print(value)
}
switch data.result {
case .success(_):
do {
let dictionary = try JSONSerialization.jsonObject(with: data.data!, options: .fragmentsAllowed) as! NSDictionary
print("Success!")
print(dictionary)
}
catch {
// catch error.
print("catch error")
}
break
case .failure(_):
print("failure")
break
}
}).cURLDescription { description in
print(description)
}
}

Related

how to upload image (Multipart) using Alamofire 5.0.0-beta.3 (Swift 5)

I am working on uploading image using multipart. This Code Working fine in swift 4 and Alamofire 4. Please give any solution for this.
public class func callsendImageAPI(param:[String: Any],arrImage:[UIImage],imageKey:String,URlName:String,controller:UIViewController, withblock:#escaping (_ response: AnyObject?)->Void){
Alamofire.upload(multipartFormData:{ MultipartFormData in
for (key, value) in param {
MultipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
for img in arrImage {
guard let imgData = img.jpegData(compressionQuality: 1) else { return }
MultipartFormData.append(imgData, withName: imageKey, fileName: FuncationManager.getCurrentTimeStamp() + ".jpeg", mimeType: "image/jpeg")
}
},usingThreshold:UInt64.init(),
to: "URL",
method:.post,
headers:["Content-type": "multipart/form-data",
"Content-Disposition" : "form-data"],
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, , ):
upload.uploadProgress(closure: { (Progress) in
print("Upload Progress: \(Progress.fractionCompleted)")
})
upload.responseJSON { response in
switch(response.result) {
case .success(_):
let dic = response.result.value as! NSDictionary
if (dic.object(forKey: "status")! as! Int == 1){
withblock(dic.object(forKey: "data") as AnyObject)
}else if (dic.object(forKey: Message.Status)! as! Int == 2){
print("error message")
}else{
print("error message")
}
case .failure(_):
print("error message")
}
}
case .failure(let encodingError):
print("error message")
}
})}
Thanks in advance.
Almofire 5.0 & Swift 5.0
//Set Your URL
let api_url = "YOUR URL"
guard let url = URL(string: api_url) else {
return
}
var urlRequest = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 10.0 * 1000)
urlRequest.httpMethod = "POST"
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
//Set Your Parameter
let parameterDict = NSMutableDictionary()
parameterDict.setValue(self.name, forKey: "name")
//Set Image Data
let imgData = self.img_photo.image!.jpegData(compressionQuality: 0.5)!
// Now Execute
AF.upload(multipartFormData: { multiPart in
for (key, value) in parameterDict {
if let temp = value as? String {
multiPart.append(temp.data(using: .utf8)!, withName: key as! String)
}
if let temp = value as? Int {
multiPart.append("\(temp)".data(using: .utf8)!, withName: key as! String)
}
if let temp = value as? NSArray {
temp.forEach({ element in
let keyObj = key as! String + "[]"
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(imgData, withName: "file", fileName: "file.png", mimeType: "image/png")
}, with: urlRequest)
.uploadProgress(queue: .main, closure: { progress in
//Current upload progress of file
print("Upload Progress: \(progress.fractionCompleted)")
})
.responseJSON(completionHandler: { data in
switch data.result {
case .success(_):
do {
let dictionary = try JSONSerialization.jsonObject(with: data.data!, options: .fragmentsAllowed) as! NSDictionary
print("Success!")
print(dictionary)
}
catch {
// catch error.
print("catch error")
}
break
case .failure(_):
print("failure")
break
}
})
Happy to help you :)
Its Work for me
Please refer Below code.
public class func callsendImageAPI(param:[String: Any],arrImage:[UIImage],imageKey:String,URlName:String,controller:UIViewController, withblock:#escaping (_ response: AnyObject?)->Void){
let headers: HTTPHeaders
headers = ["Content-type": "multipart/form-data",
"Content-Disposition" : "form-data"]
AF.upload(multipartFormData: { (multipartFormData) in
for (key, value) in param {
multipartFormData.append((value as! String).data(using: String.Encoding.utf8)!, withName: key)
}
for img in arrImage {
guard let imgData = img.jpegData(compressionQuality: 1) else { return }
multipartFormData.append(imgData, withName: imageKey, fileName: FuncationManager.getCurrentTimeStamp() + ".jpeg", mimeType: "image/jpeg")
}
},usingThreshold: UInt64.init(),
to: URL.init(string: URlName)!,
method: .post,
headers: headers).response{ response in
if((response.error != nil)){
do{
if let jsonData = response.data{
let parsedData = try JSONSerialization.jsonObject(with: jsonData) as! Dictionary<String, AnyObject>
print(parsedData)
let status = parsedData[Message.Status] as? NSInteger ?? 0
if (status == 1){
if let jsonArray = parsedData["data"] as? [[String: Any]] {
withblock(jsonArray as AnyObject)
}
}else if (status == 2){
print("error message")
}else{
print("error message")
}
}
}catch{
print("error message")
}
}else{
print(response.error!.localizedDescription)
}
}
}
Happy to help you :)

Upload files with parameters from multipartformdata using alamofire 5 in ios swift

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)
}
})
}

How to upload image data with some extra parameters to server via POST call using Swift 4.2?

My scenario, I am trying to send some parameters with Image Data to server using POST call. Here, I need to update my code Parameters to Body request, because Image base64 string huge data producing so we cant send long lenth data with it. Please update blow code how to upload image and extra parameters to Server.
apiPath = "https://............com/api/new_line?country=\(get_countryID ?? "unknown")&attachment=\("sample.png")&user_id=\(userid ?? "unknown")"
if let encodeString = apiPath.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed),
let url = URL(string: encodeString) {
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue(access_key, forHTTPHeaderField: "access-key")
request.addValue(auth_token!, forHTTPHeaderField: "auth-token")
request.timeoutInterval = 10
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else {return}
guard let data = data else {return}
do {
//MARK: Create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print(json)
// MARK: Validate status code
let status_code : Int = json["status"]! as! Int
let status_message : String = json["message"]! as! String
if (status_code != 200) {
print("ERROR:\(String(describing: status_code))")
DispatchQueue.main.async {
self.showMessageToUser(messageStr: status_message)
}
} else {
DispatchQueue.main.async {
// Show Success Alert View Controller
if self.tfData != "" { // Call Update
self.apistatus(message:Updated Successfully!")
} else {
self.apistatus(message:"Submitted Successfully!")
}
}
}
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
}
You can try using Alamofire (https://github.com/Alamofire/Alamofire) as below.
Alamofire.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(photoData, withName: "photoId", fileName: "photoId.png", mimeType: "image/png")
for (key,value) in params { //params is a dictionary of values you wish to upload
multipartFormData.append(value.data(using: .utf8)!, withName: key)
}
},
to: URL(string : urlString)!,
method: .post,
headers: getContentHeader(),
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
if response.response?.statusCode == 200 {
print("Success")
} else {
print("Failure")
}
}
case .failure(let error):
print("Failure")
}
}
)
// Iam use alamofire Method
func sendIMAGeAndParams(urlString:String,imageData:[String:[Data]],header: String,params:[String:AnyObject], success: #escaping (AnyObject) -> Void,failure: #escaping(Error) -> Void) {
let param = ["" : ""]
let url = try! URLRequest.init(url: urlString, method: .post, headers: nil)
Alamofire.upload(multipartFormData: { (formdata) in
for (key, value) in params {
formdata.append("\(value)".data(using: String.Encoding.utf8)!, withName: key)
}
for (key,value) in imageData{
for item in value{
formdata.append(item, withName: key, fileName: "image.jpeg", mimeType: "image/jpeg")
}
}
}, with: url) { (encodingResult) in
switch encodingResult{
case .success(let upload,_,_):
upload.responseJSON(completionHandler: { (response) in
switch response.result{
case .success(_):
if (response.response?.statusCode == 200){
if let value = response.result.value {
success(value as AnyObject)
print(value)
}
}
else{
let value = response.result.value as? [String:Any]
print(value as Any)
}
break
case .failure(let error):
print(error)
break
}
})
break
case .failure(let error):
print(error)
break
}
}
}

Alamofire file upload getting error "JSON text did not start with array or object and option to allow fragments not set"

Below is my code referring this question answer
func createRequest(ResumeID: String, CandidateID: String, MediaName: String, FileExtension : String, MediaType : String) throws -> URLRequest {
let parameters = NSDictionary(objects: [ResumeID, CandidateID, MediaName, FileExtension,MediaType], forKeys: ["ResumeID" as NSCopying, "CandidateID" as NSCopying, "MediaName" as NSCopying, "FileExtension" as NSCopying, "MediaType" as NSCopying])
let boundary = generateBoundaryString()
let url = URL(string: "http://192.168.1.29/ColorsKit_New_Svr/WTCSvr.svc/WTCService?Id=6&SPName=Usp_RTN_IU_CandidateSubmissionResume")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let path1 = Bundle.main.path(forResource: "dummy-pdf_2", ofType: "pdf")!
request.httpBody = try createBody(with: parameters as? [String : String], filePathKey: "MediaContent", paths: [path1], boundary: boundary)
return request
}
private func createBody(with parameters: [String: String]?, filePathKey: String, paths: [String], boundary: String) throws -> Data {
var body = Data()
if parameters != nil {
for (key, value) in parameters! {
body.append("--\(boundary)\r\n")
body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.append("\(value)\r\n")
}
}
for path in paths {
let url = URL(fileURLWithPath: path)
let filename = url.lastPathComponent
let data = try Data(contentsOf: url)
let mimetype = mimeType(for: path)
body.append("--\(boundary)\r\n")
body.append("Content-Disposition: form-data; name=\"\(filePathKey)\"; filename=\"\(filename)\"\r\n")
body.append("Content-Type: \(mimetype)\r\n\r\n")
body.append(data)
body.append("\r\n")
}
body.append("--\(boundary)--\r\n")
return body
}
func sendMultipartRequest() {
let request: URLRequest
do {
request = try createRequest(ResumeID: "1", CandidateID: "1241124", MediaName: "dummy-pdf", FileExtension: "pdf", MediaType: "pdf")
} catch {
print(error)
return
}
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
// handle error here
print(error!)
return
}
// if response was JSON, then parse it
do {
let responseDictionary = try JSONSerialization.jsonObject(with: data!)
print("success == \(responseDictionary)")
// note, if you want to update the UI, make sure to dispatch that to the main queue, e.g.:
//
// DispatchQueue.main.async {
// // update your UI and model objects here
// }
} catch {
print(error)
let responseString = String(data: data!, encoding: .utf8)
print("responseString = \(String(describing: responseString))")
}
}
task.resume()
}
The Response I'm getting is:
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start
with array or object and option to allow fragments not set."
UserInfo={NSDebugDescription=JSON text did not start with array or
object and option to allow fragments not set.} responseString =
Optional("No Records Found")
This is strange because Postman is giving correct response. Means there is something missing in the code only :(
Use Alamofire
let upload_url = "your url"
let fieldName = "UploadedFile"
let mimeType = "plain/text"
Alamofire.upload(multipartFormData: { multipartFormData in
//you can add multiple file
multipartFormData.append(fileData as Data, withName: fieldName, fileName: fileName, mimeType: mimeType)
}, to: upload_url, method: .post, headers: ["Authorization": "auth_token"],
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.response { [weak self] response in
guard let _ = self else {
return
}
debugPrint(response)
}
case .failure(let encodingError):
debugPrint("uploaderService error:\(encodingError)")
}
})
Use JSONSerialization as below
if let responseDictionary = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String {
...
}

How to upload multiple images in multipart using Alamofire?

I am stuck in uploading multiple images in multipart using Alamofire. Can any one help me?
Thanks in advance!!
For more details, I am using this code to create body part of images data:
func imageArrayToNSData(array: [UIImage],boundary:String) -> NSData {
let body = NSMutableData()
var i = 0;
for image in array{
let filename = "image\(i).jpg"
let data = UIImageJPEGRepresentation(image,0.8);
let mimetype = "image/jpeg"
let key = "product_images"
body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("Content-Disposition: form-data; name=\"\(key)\"; filename=\"\(filename)\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("Content-Type: \(mimetype)\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(data!)
body.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
i += 1
}
body.appendData("--\(boundary)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
return body
}
to upload I am using :
Alamofire.upload(.POST, EDIT_PRODUCT_URL, headers: ["Accept": "application/json","Content-Type":"application/json"], multipartFormData: { (formData) in
if productImages.count>0{
let boundary = generateBoundaryString()
let imageData = CommonClass.imageArrayToNSData(productImages,boundary: boundary)
formData.appendBodyPart(data: imageData, name: "product_images", mimeType: "image/jpeg")
}
for (key, value) in params {
if value is [String]{
let data = CommonClass.stringArrayToNSData(value as! [String])
formData.appendBodyPart(data:data , name: key)
}else if value is String{
formData.appendBodyPart(data: value.dataUsingEncoding(NSUTF8StringEncoding)!, name: key)
}else if let v = value as? Bool{
var bValue = v
let d = NSData(bytes: &bValue, length: sizeof(Bool))
formData.appendBodyPart(data: d, name: key)
}
}
}) { (encodingResult) in
switch encodingResult {
case .Success(let upload, _, _):
KVNProgress.showProgress(CGFloat(0), status:"0% Sent")
upload.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
// This closure is NOT called on the main queue for performance
// reasons. To update your ui, dispatch to the main queue.
dispatch_async(dispatch_get_main_queue()) {
let prg = Int((CGFloat(totalBytesWritten)*100)/CGFloat(totalBytesExpectedToWrite))
if prg == 100{
KVNProgress.showSuccessWithStatus("Created")
}
KVNProgress.updateStatus("\(prg)% Sent")
KVNProgress.updateProgress(CGFloat(Float(prg)/100.0), animated: true)
}
}
upload.responseJSON { response in
CommonClass.hideLoader()
switch response.result {
case .Success:
if let value = response.result.value {
let json = JSON(value)
print_debug("edit Product JSON is\n\(json)");
completionBlock(json)
}else{
completionBlock(nil)
}
case .Failure(let error):
print_debug(error.description)
showErrorWithMessage("Oops! Couldn't connect to server!")
completionBlock(nil)
}
}
case .Failure(let encodingError):
print(encodingError)
}
}
Can any one please let me suggest the way to upload multiple files in multipart using Alamofire?
In Swift 3 and above
Just append "[]" with image key identifier to treat it as array of images.
Alamofire.upload(multipartFormData: { multipartFormData in
// import image to request
for imageData in imagesData {
multipartFormData.append(imageData, withName: "\(imageParamName)[]", fileName: "\(Date().timeIntervalSince1970).jpeg", mimeType: "image/jpeg")
}
for (key, value) in parameters {
multipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
}
}, to: urlString,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
}
case .failure(let error):
print(error)
}
})
I Hope it will be helpful for you:
Using Swift 3x: (I have uploaded four Photos in this snippet)
//MARK: - upload multiple photos
func uploadImagesAndData(params:[String : AnyObject]?,image1: UIImage,image2: UIImage,image3: UIImage,image4: UIImage,headers : [String : String]?, completionHandler:#escaping CompletionHandler) -> Void {
let imageData1 = UIImageJPEGRepresentation(image1, 0.5)!
let imageData2 = UIImageJPEGRepresentation(image2, 0.5)!
let imageData3 = UIImageJPEGRepresentation(image3, 0.5)!
let imageData4 = UIImageJPEGRepresentation(image4, 0.5)!
Alamofire.upload(multipartFormData: { multipartFormData in
for (key, value) in params! {
if let data = value.data(using: String.Encoding.utf8.rawValue) {
multipartFormData.append(data, withName: key)
}
}
multipartFormData.append(imageData1, withName: "file", fileName: "image.jpg", mimeType: "image/jpeg")
multipartFormData.append(imageData2, withName: "file", fileName: "image.jpg", mimeType: "image/jpeg")
multipartFormData.append(imageData3, withName: "file", fileName: "image.jpg", mimeType: "image/jpeg")
multipartFormData.append(imageData4, withName: "file", fileName: "image.jpg", mimeType: "image/jpeg")
},
to: K_BASEURL + K_API_LOGINDATA, encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload
.validate()
.responseJSON { response in
switch response.result {
case .success(let value):
print("responseObject: \(value)")
case .failure(let responseError):
print("responseError: \(responseError)")
}
}
case .failure(let encodingError):
print("encodingError: \(encodingError)")
}
})
}
1) To upload multiple image using Alamofire in Swift3
typealias APICompletionHandler = (code:Int, error:NSError?, response:AnyObject?) -> Void
func uploadIMultipart(_ strApiName:String, param : NSDictionary?, data:Array<NSDictionary>, header:[String : String]?, completionHandler:#escaping APICompletionHandler)
{
let strURL : String = strApiName
let apiURL = try! URLRequest(url: strURL, method: .post, headers: header)
Alamofire.upload(multipartFormData: { (multipartFormData) in
// code
var i : Int = 0
for dict:NSDictionary in data {
let extention = dict["format"] as? String
let strMimeType = dict["strMimeType"] as? String
let nameofFile:String = (6.randomString as String)+"."+extention!
if (dict["data"] as? Data != nil) {
multipartFormData.append(Foundation.Data(dict["data"] as! Data), withName: dict["key"] as! String, fileName: nameofFile , mimeType: strMimeType!)
} else {
let strUrl = dict["data"] as! String
let fileURL : URL? = URL(string: strUrl)
multipartFormData.append(try! Foundation.Data(contentsOf: fileURL!), withName: dict["key"] as! String, fileName: nameofFile , mimeType: strMimeType!)
}
i += 1
}
for (key, value) in param! {
multipartFormData.append((value as! NSString).data(using: String.Encoding.utf8.rawValue)!, withName: key as! String)
}
}, with: apiURL, encodingCompletion: { (result) in
// code
switch result {
case .success(let upload,_ ,_ ):
upload.responseJSON { response in
switch response.result {
case .success(let data):
//Sucess
case .failure(let error):
print(error.localizedDescription)
}
}
case .failure(let encodingError):
print(encodingError)
completionHandler(0, encodingError as NSError?, nil)
}
})
}
2) To call Function
let imageData : NSData = UIImagePNGRepresentation(imgUserProfile.image!)! as NSData
let imageData1 : NSData = UIImagePNGRepresentation(imgUserProfile.image!)! as NSData
let dict1: Dictionary = ["data":imageData,"key":"user_image", "format":"jpg", "strMimeType":"image/jpeg"] as [String : Any]
let dict2: Dictionary = ["data":imageData1,"key":"image1", "format":"jpg", "strMimeType":"image/jpeg"] as [String : Any]
let array: Array = [dict1,dict2]; //pass this image array
self.uploadIMultipart(strAPI, param: dictParam as NSDictionary, data: array as Array<NSDictionary>, header: nil) { (code, error, response) in
AppSingletonObj.stopLoading(inView: self.view)
//API manager sucess or failure
if code == 1 {
let status = response?["success"]
//API sucess or failure
if(status as! Int == 1) {
print(response!)
}
else {
let errorMessage = response?["message"]
AppSingletonObj.showAlert(msg: errorMessage as! String)
}
}
else {
AppSingletonObj.showAlert(msg: "Some error occured! please try after sometime")
}
}
3) Extension to create file name
//MARK: CREATE RANDOM STRING of LENGTH
extension Int{
var randomString : String {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let randomString : NSMutableString = NSMutableString(capacity: self)
for _ in 0 ..< self{
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.character(at: Int(rand)))
}
return randomString as String
}
}
To upload multiple image you need to call this code in loop
let boundary = generateBoundaryString()
let imageData = CommonClass.imageArrayToNSData(productImages,boundary: boundary)
formData.appendBodyPart(data: imageData, name: "product_images", mimeType: "image/jpeg")
Swift 4.2.
Here code is only for without any parameters.
If you need to pass extra parameters just go with #Hardik Thakkar code.
typealias APICompletionHandler = (code:Int, error:NSError?, response:AnyObject?) -> Void
#IBOutlet weak var thirdImage: UIImageView!
var fristImage:UIImage = UIImage()
var secondimage:UIImage = UIImage()
extension ViewController {
func upload() {
let imgData1 = fristImage.jpegData(compressionQuality: 0.7)
let imgData2 = secondimage.jpegData(compressionQuality: 0.7)
let imgData3 = thirdImage.image!.jpegData(compressionQuality: 0.7)
let headers = [
"Authorization" : "Bearer " + "Your Token",
"Content-type": "form-data",
]
let dict1: Dictionary = ["data":imgData1 as Any,"key":"Here Your Body Key1", "format":"jpg", "strMimeType":"image/jpeg"] as [String : Any]
let dict2: Dictionary = ["data":imgData2 as Any,"key":"Here Your Body Key2", "format":"jpg", "strMimeType":"image/jpeg"] as [String : Any]
let dict3: Dictionary = ["data":imgData3 as Any,"key":"Here Your Body Key3", "format":"jpg", "strMimeType":"image/jpeg"] as [String : Any]
let array: Array = [dict1, dict2, dict3]; //pass this image array
self.uploadIMultipart("Here Your URL", data: array as Array<NSDictionary>, header: headers) { (code, error, response) in
let httpResponse = response as? HTTPURLResponse
print("the resopnse code is : \(String(describing: httpResponse?.statusCode.description))")
}
}
func uploadIMultipart(_ strApiName:String, data:Array<NSDictionary>, header:[String : String]?, completionHandler:#escaping APICompletionHandler) {
let strURL : String = strApiName
let apiURL = try! URLRequest(url: strURL, method: .post, headers: header)
Alamofire.upload(multipartFormData: { (multipartFormData) in
// code
var i : Int = 0
for dict:NSDictionary in data {
let extention = dict["format"] as? String
let strMimeType = dict["strMimeType"] as? String
let nameofFile:String = (6.randomString as String)+"."+extention!
if (dict["data"] as? Data != nil) {
multipartFormData.append(Foundation.Data(dict["data"] as! Data), withName: dict["key"] as! String, fileName: nameofFile , mimeType: strMimeType!)
} else {
let strUrl = dict["data"] as! String
let fileURL : URL? = URL(string: strUrl)
multipartFormData.append(try! Foundation.Data(contentsOf: fileURL!), withName: dict["key"] as! String, fileName: nameofFile , mimeType: strMimeType!)
}
i += 1
}
}, with: apiURL, encodingCompletion: { (result) in
// code
switch result {
case .success(let upload,_ ,_ ):
upload.responseJSON { response in
switch response.result {
case .success(let response):
//Sucess
print("response :-", response)
case .failure(let error):
//Failure
print(error.localizedDescription)
}
}
case .failure(let encodingError):
print(encodingError)
completionHandler(0, encodingError as NSError?, nil)
}
})
}
}
extension Int{
var randomString : String {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let randomString : NSMutableString = NSMutableString(capacity: self)
for _ in 0 ..< self{
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.character(at: Int(rand)))
}
return randomString as String
}
}
class func uploadImageToServer(uploadTo: String, imageParameters:[[String: Any]], otherParameters:[String: Any],authorization: String, completionHandler:#escaping ((_ responseValue: Any?, _ error: Error?) -> Void)) {
if isNetWorkAvailable() {
var urlRequest = URLRequest(url: URL.init(string: uploadTo)!)
urlRequest.httpMethod = "POST"
urlRequest.addValue(authorization, forHTTPHeaderField: "Authorization")
DispatchQueue.main.async(execute: {
ActivityIndicatorView.showActivity()
})
print("Request Url: \(uploadTo)\nRequest Params: \(imageParameters)\nRequest Params: \(otherParameters)")
Alamofire.upload(multipartFormData: { (multipartFormData) in
for (key,value) in otherParameters {
multipartFormData.append((value as! String).data(using: .utf8)!, withName: key)
}
for value in imageParameters {
let image = value["image"] as! UIImage
let imgData = UIImageJPEGRepresentation(image, 1)!
let imageName = value["imageName"] as! String
let fileName = value["fileName"] as! String
multipartFormData.append(imgData, withName: imageName, fileName: fileName ,mimeType: "image/jpeg")
}
}, usingThreshold: UInt64.init(), with: urlRequest, encodingCompletion: { (encodingResult) in
switch encodingResult {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
let uploadPercetange = Int(progress.fractionCompleted*100)
print("Upload Progress: \(uploadPercetange)%")
})
upload.responseJSON(completionHandler: { (response) in
print(response.result.value ?? "NaN")
let result = response.result.value
completionHandler(result, nil)
DispatchQueue.main.async(execute: {
ActivityIndicatorView.hideActivity()
})
})
case .failure(let encodingError):
print(encodingError)
let error = encodingError
completionHandler(nil, error)
DispatchQueue.main.async(execute: {
ActivityIndicatorView.hideActivity()
})
}
})
} else {
AlertView.showAlert(title: "Error", message: "Network not available")
}
}

Resources