Swift 3 Alamofire POST with Headers Parameters, Query Parameters, and Request Body - swift

I am faily new to Alamofire itself, so forgive me if this is a simple one.
I would like to post a bank account object to intuit payments using Alamofire, however I keep getting the following error:
Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.}
The documentation notes the following:
REQUEST URL
Sandbox Base URL: https://sandbox.api.intuit.com
Production Base URL: https://api.intuit.com
Operation: POST /quickbooks/v4/customers/<id>/bank-accounts
Content type: application/json
Header Parameters:
Request-Id required
Query Parameters:
id required
Request body
{
"name": "My Checking",
"routingNumber": "XXXXX0358",
"accountNumber": "XXXX4534",
"accountType": "PERSONAL_CHECKING",
"phone": "6047296480"
}
My attempts are as follows:
func saveBankAccountToIntuitPayments() {
let url = "https://api.intuit.com/quickbooks/v4/customers/" + userID! + "/bank-accounts"
let parameters: Parameters = [
"name": "John Doe",
"routingNumber": "123321456",
"accountNumber": "432123789012",
"accountType": "PERSONAL_CHECKING",
"phone": "55568925029"
]
ATTEMPT 1
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default).responseJSON(completionHandler: {
response in
print("running self.parseData(JSONData: response.data!)")
self.parseData(JSONData: response.data!)
})
ATTEMPT 2
let requestId = userID! + getTimeNow()
let header = [ "Request-Id" : requestId ]
Alamofire.request(url: url, method: .post, headers: header, parameters: parameters, encoding: JSONEncoding.default).responseJSON(completionHandler: {
response in
print("running self.parseData(JSONData: response.data!)")
self.parseData(JSONData: response.data!)
})
ATTEMPT 3
request(url, method: .post, parameters: parameters, headers: header).responseJSON(completionHandler: {
response in
print("running self.parseData(JSONData: response.data!)")
self.parseData(JSONData: response.data!)
})
}
This is the code for my json parser:
func parseData(JSONData: Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONStandard
print("printing readable JSON (below)")
print(readableJSON ?? "no JSON data was returned")
} catch {
print("errror occured (below)")
print(error)
}
}

Related

How to send an array of json as value for multipart/form-data content type?

Guys I need to send parameters described in the image value where content type is multipart/form-data. Im having difficulty in sending only package_json parameter.
The problem is I don't know how do I send multiple package_json values as parameter? I can send one value like this:
let param = [
"outletId : "1",
"vehicleId" : "1",
"instructions" : tvInstructions.text,
"package_json" : "[{\"packageId\":\"1\"}]",
"addressId" : "1"
]
Above i'm able to send package_json = [{"packageId": 1}] as String as my function below sends parameters as [String : String] and images of Data type as [String : Any]. Im having problem sending multiple values in package_json. For eg. something like this: [{"packageId": 1}, {"packageId": 2}, {"packageId": 3}] and so on. Here's the function that i'm using to send parameters:
func postrequest(_ request: String, onPath imagesData:[Data]?,_ imageName : String, andParameter parameters: [String:String]?, withCompletion response: #escaping serviceCompletion) {
let headers: HTTPHeaders
headers = ["Content-type": "multipart/form-data"]
AF.upload(multipartFormData: { multiPart in
if let allParams = parameters {
for (key, value) in allParams {
multiPart.append(value.data(using: .utf8)!, withName: key)
}
}
for imageData in imagesData ?? [] {
multiPart.append(imageData, withName: "\(imageName)", fileName: "file.jpg", mimeType: "image/jpg")
}
}, to: request, usingThreshold: UInt64.init(),
method: .post,
headers: headers).response { (res) in
if((res.error == nil)){
do {
response(res.data,res.error)
}
}
else{
// hideHud()
response(res.data,res.error)
}
}
}
I tried to convert function to send [String: Any] data but found out we can only send as [String : String] along with images as [String : Any].
I just want to know if there is any way to modify "package_json" : "[{\"packageId\":\"1\"}]" so I can send [{"packageId": 1}, {"packageId": 2}, {"packageId": 3}]?
Just in case, this is how im calling above function and sending parameters:
func sendData() {
let param = [
"outletId" : "1",
"vehicleId" : "1",
"instructions" : tvInstructions.text,
"package_json" : "[{\"packageId\":\"1\"}]",
"addressId" : "1"
]
ApiNetworkManager.shared.postrequest(Api.completeUrl, onPath: [], "", andParameter: param) { (response, err) in
ApiNetworkManager.shared.hideHud()
debugPrint(param)
let json = JSON.init(response!)
debugPrint(json)
if err == nil {
if err == nil && response != nil {
if json.dictionaryValue["success"]?.stringValue == "1" {
//Add your code here
}
else{
let message = json.dictionaryValue["message"]?.stringValue
self.showAlert(Message: message ?? "Error")
}
} else {
// hideHud()
print(err?.localizedDescription as Any)
let message = json.dictionaryValue["message"]?.stringValue
self.showAlert(Message: message ?? "Error")
}
}
else{
ApiNetworkManager.shared.hideHud()
let message = err?.localizedDescription
self.showAlert(Message: message ?? "Error")
}
}
}

Swift AlamoFire PUT request

I have a JSON file with this struct:
{
"example": {
"projects": [
{ "projectname" : "abc",
"date" : "20200930",}
{ "projectname" : "bac",
"date" : "20200803",}
]
}
}
I want to update first projectname, but not the date connected to it. But the AF.request method give me back error 400 (Invalid JSON body passed.)
let user = "username"
let password = "password"
let params = ["example":
["projects":
["projectname": "New Name"]
]
]
let credentialData = "\(user):\(password)".data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!
let base64Credentials = credentialData.base64EncodedString()
let headers : HTTPHeaders = [
"Authorization": "Basic \(base64Credentials)",
"Accept": "application/json",
"Content-Type": "application/json" ]
AF.request("https://example.com/api", method: .put, parameters: params, headers: headers).responseJSON { AFdata in
do {
guard let jsonObject = try JSONSerialization.jsonObject(with: AFdata.data!) as? [String: Any] else {
print("Error: Cannot convert data to JSON object")
return
}
guard let prettyJsonData = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) else {
print("Error: Cannot convert JSON object to Pretty JSON data")
return
}
guard let prettyPrintedJson = String(data: prettyJsonData, encoding: .utf8) else {
print("Error: Could print JSON in String")
return
}
print(prettyPrintedJson)
} catch {
print("Error: Trying to convert JSON data to string")
return
}
}
Thanks for your help!
I believe you are missing the encoder parameter in you request:
AF.request("https://example.com/api", method: .put, parameters: params, headers: headers, encoder: JSONParameterEncoder.default).responseJSON { AFdata in
Without it Alamofire cannot know that your parameters should be encoded as JSON.

Uploading multiple images(with parameters) using multipart form data - Alamofire 5

I have been trying to upload multiple images(3) with parameters using alamofire but i cant seem to do it.(My lack of knowledge). Could someone kindly help me out with this?
This is what i have tried
{
let headers: HTTPHeaders = [
xyz
]
let param : [String: Any] = [
"emp_Id" : "",
"device_Identifier" : "",
"timestamp" : "",
"description" : "",
"handoverStatus" : ""
]
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(imgData0, withName: "media1" , fileName: "file0.jpeg", mimeType: "image/jpeg")
multipartFormData.append(imgData1, withName: "media2",fileName: "file1.jpg", mimeType: "image/jpg")
multipartFormData.append(imgData2, withName: "media3",fileName: "file1.jpg", mimeType: "image/jpg")
// I think im supposed to add the last part here but i dunno how to do that
},
to: "http://ip.here.--.--/new.php", method: .post , headers: headers)
.response { resp in
print(resp)
}
}
This is what the server expects
[{"key":"media1","description":"","type":"file","value":["/C:/Users/x/x/Saved Pictures/x.jpg"]},
[{"key":"media2","description":"","type":"file","value":["/C:/Users/x/x/Saved Pictures/x.jpg"]},
[{"key":"media3","description":"","type":"file","value":["/C:/Users/x/x/x.jpg"]},
{"key":"model","value":"{\"emp_Id\": \"6\",\"device_Identifier\":\"Device 01\",\"timestamp\":\"\123\,
”\description\”:\”description\",”handoverStatus”:”false”}","type":"text"}]
I dunno how to add the last part to the multipart form data, could some point me in the right direction ?
Thanks
Try this method to upload multiple images
class func uploadImageWithURL(endPath : String, dictImage : [String:[UIImage]], parameter : [String : Any], header : HTTPHeaders? = nil, success : #escaping ( Any? )->Void, failure : #escaping (Error) -> Void){
let baseUrl = "your base URL"
let fullUrl = baseUrl + endPath
var headers = ["Content-type" : "multipart/form-data"]
if let header = header{
headers = header
}
let url = (try? URLRequest(url: fullUrl, method: .post, headers: headers))!
upload(multipartFormData: { (multipartData) in
for imagesData in dictImage {
for arrimage in imagesData.value{
multipartData.append(arrimage.jpegData(compressionQuality: 0.50)!, withName: imagesData.key, fileName: "\(Date().timeIntervalSince1970).jpg", mimeType: "image/jpeg")
}
}
for (key, value) in parameter {
multipartData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
}, with: url) { (resultData) in
switch resultData{
case .success(let upload, let streamingFromDisk, let fileURL):
print("File URL : \(String(describing: fileURL))")
print("Streaming From Disk : \(streamingFromDisk)")
upload.uploadProgress(closure: { (progress) in
print("Progress : \(progress.fractionCompleted)")
})
upload.responseJSON(queue: nil, options: .allowFragments, completionHandler: { (response) in
if let value = response.result.value
{
success(value)
}
})
case .failure(let error):
failure(error)
print(error)
}
}
}

Send JSON array as a parameter Alamofire

I'm having difficulty with a parameter which contains a Json array using Alamofire
Here is a string of my Json:
"[{\"id\":546836102,\"count\":1},{\"id\":216479424,\"count\":1}]"
Here is my code where I make the request:
let data = (params["cart"] as! String).data(using: .utf8)!
do {
if let jsonArray = try JSONSerialization.jsonObject(with: data, options : .fragmentsAllowed) as? [Dictionary<String, Int>] {
let parameters: Parameters = [
"address_id": params["address_id"] as! Int,
"delivery_day": params["delivery_day"] as! String,
"delivery_hour": params["delivery_hour"] as! Int,
"cart": jsonArray,
"via": params["via"] as! String
]
Alamofire.request(Global.baseURL + "orders/finish", method: .post, parameters: parameters, encoding: URLEncoding.default, headers: header)
.responseSwiftyJSON {
Printing out my parameters
["cart": [["id": 546836102, "count": 1], ["count": 1, "id": 216479424]], "address_id": 641589205, "delivery_day": "1399-01-20", "delivery_hour": 21, "via": "ios"]
Backend must receive the cart as below:
[
{
"id": 123456,
"count": 2
},
{
"id": 654321,
"count": 3
}
]
But instead it gets the data like this:
{
"delivery_hour" : "21",
"delivery_day" : "1399-01-20",
"cart" : [
{
"count" : "1"
},
{
"id" : "546836102"
},
{
"count" : "1"
},
{
"id" : "216479424"
}
],
"via" : "ios",
"address_id" : "641589205"
}
I have tried JSONEncoding and URLEncoding options by Alamofire but nothing seems to work and this is the closest I've gotten to the API template so far.
What am I doing so wrong here?
// MARK: - Update
So I updated to the latest version of Alamofire and still no good results :(
Here is the code:
let payload = MyParameters(address_id: 641589205, delivery_day: "1399-01-21", delivery_hour: 21, cart: items, via: "ios")
AF.request(url, method: .post, parameters: payload, encoder: JSONParameterEncoder.default, headers: .init(header), interceptor: nil).response { dataResponse in
switch dataResponse.result {
case .success(let value):
if dataResponse.response?.statusCode == 200 {
let json = JSON(value!)
completionHandler(json, nil)
} else {
print(dataResponse.response?.statusCode ?? -1)
}
case .failure(let error):
print(error)
completionHandler(nil, error.localizedDescription)
}
}
My payload looks exactly what I want it to be
{
"cart" : [
{
"count" : 1,
"id" : 546836102
},
{
"count" : 1,
"id" : 216479424
}
],
"via" : "ios",
"address_id" : 641589205,
"delivery_day" : "1399-01-21",
"delivery_hour" : 21
}
But then again the endpoint receives this:
{
"{\"delivery_day\":\"1399-01-21\",\"address_id\":641589205,\"delivery_hour\":21,\"cart\":" : {
"{\"id\":546836102,\"count\":1},{\"id\":216479424,\"count\":1}" : null
}
}
Using Alamofire 4, you can't send arrays using the method you've shown, as the Parameters type is [String: Any]. You're also not using the correct ParameterEncoding. If you want to send a JSON body, you need to use the JSONEncoding. What you can do is manually serialize the array into a URLRequest and make that request using Alamofire.
Additionally, if you update to Alamofire 5, Encodable parameters are now supported, so you if you can define your parameters as an Encodable type, sending them would be as easy as passing an array.
AF.request(..., parameters: [some, encodable, values], encoder: JSONEncoder.default)...

how to set multipart "withname" with dictionary in swift?

I want to send the images to the server with multipart form. Normal
image uploading is working with the multipart but facing the
problem is when I need to set withname with array inside dictionary.
alamofireManager.upload(multipartFormData: { multipartFormData in
for i in 0..<images.count {
let imgData = UIImagePNGRepresentation(images[i])!
multipartFormData.append(imgData, withName: "fileUpload",fileName: "\(images)i", mimeType: "image/png")
}
Server parameters are like
"documants" : [{
"documentType" : "Image",
"fileUpload: "" // multipart data
},{
"documentType" : "Image",
"fileUpload: "" // multipart data
}]
So how to mention the node name documents[0].fileUpload with withName using multipartFormData?
You can implement 'multipart' in this way...using Swift4.2
let headers: HTTPHeaders = [
/* "Authorization": "your_access_token", in case you need authorization header */
"Content-type": "multipart/form-data"
]
let url = try! URLRequest(url: baseURL, method: .post, headers: headers)
Alamofire.upload(multipartFormData: { multipartFormData in
multipartFormData.append(img, withName: "file", fileName: imgName, mimeType: "\(fileType ?? "jpg")")
}, with: url) { result in
switch result {
case .success(let upload, _, _):
upload.responseString { response in
switch (response.response?.statusCode)
{
case 200: //The request was fulfilled
print("Network - HandShaking Successfull...!!!")
debugPrint(response)
}
case .failure(let encodingError):
print(encodingError)
}
}
Hope you will get idea of 'multipart'...!!!