Issue while sending array of dictionary in swift - ios

I am creating array of dictionaries and then passing that in paramDictionary and sending to server but I get responseStatus code 422. I am using Alamofire 5.
Here is the structure of param which I have to send and it successfully working on postman but in app it is always fails
{"check_in": [{"check_in_at":"2020-02-26 03:23:44", "gps_coordinates":"3.1697998046875,101.61672197976593"},
{"check_in_at":"2020-02-26 03:23:45","gps_coordinates":"3.1697998046875,101.61672197976593"}]}
Here is my code
func postCheckInApi(viewController: UIViewController,
completion:#escaping (_ result:SuccessErrorData)->(),
errorHandler:#escaping (_ result:Error,_ statusCode:Int?)->()//error handler
) {
let url = KCheckin
let geoArr = Constant.getSearchLocationHistory() ?? [GeoTaggingEntity]()
var arr = [[String: String]]()
for i in geoArr{
let dict: [String : String] = ["gps_coordinates" : i.gps_coordinates ?? "", "check_in_at" : i.check_in_at]
arr.append(dict)
}
let parameterDictionary = ["check_in": arr] as [String : Any]
print(parameterDictionary)
let headers: HTTPHeaders = [
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": Constant.getBearerToken() ?? ""
]
AF.request(url, method: .post, parameters: parameterDictionary, headers: headers).responseData { response in
switch response.result{
case.success(let data):
do{
let jsonData = try JSONDecoder().decode(SuccessErrorData.self, from: data)
print("Success")
completion(jsonData)
}
catch{
//viewController.navigationController?.popToRootViewController(animated: true)
}
case .failure(let error):
print(error)
}
}
}

You can not add Array as parameter object to your paramDictionary. You need to covert your Array to json string and then add it to you paramDictionary.
For that use below Collection extension to convert your Array to Json String
extension Collection {
func json() -> String? {
guard let data = try? JSONSerialization.data(withJSONObject: self, options: []) else {
return nil
}
return String(data: data, encoding: String.Encoding.utf8)
}
}
How To Use
let jsonStr = yourArray.json()
add this jsonStr to your paramDictionary

Related

JSONSerialization.jsonObject returning nil?

Note: I am on step 2.3 here, I am working to integrate stripe with firebase.
I have the following guard let, which will fail. It fails because of the json const.
guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let accountURLString = json["url"] as? String, let accountURL = URL(string: accountURLString) else {
// handle error
print(": jsonfdshkfdbsh :")
return
}
Unfortunately the following declaration within it fails:
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
What is wrong with the line? How can I make it work?
Update: (What I have tried but has not worked)
let data = data as Data?
print(data, " datavar")//has a value (not nil)
let json = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String : Any]
print(json, " jsonvar") //nil
let accountURLString = json!["url"] as? String
let accountURL = URL(string: accountURLString!)
Update 2:
I've been wondering and investigating whether the problem may be that request variable path may not be valid(?). However, my testing, with a value I know exists in the database, has not yielded (worked) any results.
if let url = URL(string: backendAPIBaseURL)?.appendingPathComponent("stripe_customers/IYNpofaWUFXfobmFRLMLIEZXxqN2") {// usually the string is: "onboard-user"
var request = URLRequest(url: url)
request.httpMethod = "POST"
print(URLSession.shared.dataTask(with: request), "<-- ay un problem?")
print(request, " this was the request value")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
print("does thsi run??? ", data)
let data: Data = data!// as Data?
print(data, " ttekjfdsjklfhdas")
//...
The problem turned out to be associated with Update 2. The request was the problem.
I ended changing the code to the following, which worked:
func createStripeConnectAccount(uid: String, completion: #escaping(String?, String?) -> Void) { //accountID, Error
let parameters: [String:Any] = [:]
let url = "https://us-central1-name-fhdskj.cloudfunctions.net/createConnectAccount"
AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: [:]).responseJSON { response in
switch response.result {
case .success(let dict):
print(dict)
let successDict: [String: Any?] = dict as! [String: Any?]
let body = successDict["body"] as! [String: Any?]
let acctNum = body["success"] as! String
print(acctNum, "<-- link did it twerk?")
completion(acctNum, nil)
case .failure(let error):
print(error.localizedDescription)
completion(nil, error.localizedDescription)
}
}
}
func createAccountLink(accountID: String, completion: #escaping(String?, String?) -> Void) { //url, Error
let parameters: [String:Any] = ["accountID": accountID]
let url = "https://us-central1-name-fdsad.cloudfunctions.net/createStripeAccountLink"
AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: [:]).responseJSON { response in
switch response.result {
case .success(let dict):
print(dict)
let successDict: [String: Any?] = dict as! [String: Any?]
let body = successDict["body"] as! [String: Any?]
let link = body["success"] as! String
print(link, "<-- link did it twerk?")
completion(link, nil)
case .failure(let error):
print(error.localizedDescription)
completion(nil, error.localizedDescription)
}
}
}
You'll have to integrate Alomofire Pod.

Swift 4 - Alamofire post request with httpbody

I have this Alamofire post request like so:
var jsonArrayOfDictionaries = [[AnyHashable: Any]]()
let user = appDelegate.username
let password = appDelegate.password
let url = webservice + "PostTasks"
let credential = URLCredential(user: user!, password: password!, persistence: .forSession)
let headers = ["Accept": "application/json;odata=verbose", "Content-type": "application/json;odata=verbose"]
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: jsonArrayOfDictionaries, options: .prettyPrinted)
print(jsonData!)
//request.httpBody = jsonData
Alamofire.request(url, method: .post, headers: headers).authenticate(usingCredential: credential).responseJSON {
(response) in
switch response.result {
case .success:
if let value = response.result.value {
print(value)
OperationQueue.main.addOperation({
completion(true)
})
}else{
print("There is error in the server response")
completion(false)
}
case .failure (let error):
print("The NTLM request error is: ", error.localizedDescription)
completion(false)
}
}
My question is how do I add the jsonData variable to the httpbody of this request? I have looked into this issue and all the solutions appear to be old. Please help!
This is how jsonArrayOfDictionaries is getting populated:
var jsonArrayOfDictionaries = [[AnyHashable: Any]]()
for i in 0..<cellHolder.count {
var jsonDict = [AnyHashable: Any]()
jsonDict["scheduleTaskID"] = cellHolder[i].scheduleTaskID
jsonDict["task"] = cellHolder[i].task
jsonDict["scheduledDate"] = cellHolder[i].scheduledDate
jsonDict["actualDate"] = cellHolder[i].actualDate
jsonDict["finishedDate"] = cellHolder[i].finishedDate
jsonDict["selected"] = (cellHolder[i].selected) ? 1 : 0
jsonDict["completedBy"] = appDelegate.username
jsonDict["sortOrder"] = cellHolder[i].sortOrder
jsonArrayOfDictionaries.append(jsonDict)
jsonDict = [AnyHashable: Any]()
}
Its in a loop and gets appended.
1. Change
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: jsonArrayOfDictionaries, options: .prettyPrinted)
to
let jsonData = try JSONSerialization.jsonObject(with: jsonArrayOfDictionaries, options: []) as? [String : Any]
2. Add jsonData to your request
Alamofire.request(url, method: .post, headers: headers, parameters: jsonData).authenticate(usingCredential: credential).responseJSON {

Alamofire doesnt allow to send object directly

My API only accepts object as the body , but alamofire only sends Dictionary as an object, which my server is not accepting requesting help
I have to call an API which is a post api using alamofire
as soon as i convert the model to dictionary and dicitionary to json
and post it Alamofire does not allow me to post a string
it allows me to send a dictionary which my api does not accept
["key":"value"]- Not acceptable
{"key":"value"}- Acceptable
Can anyone share any solution?
I am using Swift 5 , Xcode 10, Alamofire 4.8.2
do{
let d = try data.asDictionary()
jsonString = DictionaryToJSON(data: dictionary)
} catch {
print(error)
}
Alamofire.request(url, method: .post, parameters: jsonString, encoding: .utf8, headers: [: ]).responseJSON { (res) in
print(res.result)
print("Request Data \(res.request) \n Dictionary \(jsonString)")
do {
let d = try JSONDecoder().decode([OTPMessage].self, from: res.data!)
print(d[0].message)
} catch {
print(error)
}
}
// Dictionary to JSON
func DictionaryToJSON(data: [String:Any])->String {
if let theJSONData = try? JSONSerialization.data(
withJSONObject: data,
options: .prettyPrinted
),
let theJSONText = String(data: theJSONData, encoding: String.Encoding.ascii) {
print("JSON string = \n\(theJSONText)")
return theJSONText
}
else {
return ""
}
}
// Object to Dictionary
extension Encodable {
func asDictionary() throws -> [String: Any] {
let data = try JSONEncoder().encode(self)
guard let dictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else {
throw NSError()
}
return dictionary
}
}
//Struct
struct OTPMessage:Codable {
var message = String()
}
You don't have to convert your dictionary to a JSON String because Alamofire can do the encoding, see this example.
I suggest you to change your code to something like this
do{
let dictionary = try data.asDictionary()
Alamofire.request(url, method: .post, parameters: dictionary, encoding: .JSON, headers: [:]).responseJSON { (res) in
print(res.result)
print("Request Data \(res.request) \n Dictionary \(jsonString)")
do{
let d = try JSONDecoder().decode([OTPMessage].self, from: res.data!)
print(d[0].message)
}catch{
print(error)
}
}
} catch{
print(error)
}
With Alamofire you can not do this. What you need to do is creating a URLRequest object and setting the httpBody property of it and then passing it to Alamofire.
URLRequest allows you to have Data as POST body.
var request = URLRequest(url: urlFinal)
request.httpMethod = HTTPMethod.post.rawValue
request.allHTTPHeaderFields = dictHeader
request.timeoutInterval = 10
request.httpBody = newPassword.data(using: String.Encoding.utf8)
Alamofire.request(request).responseString { (response) in
if response.response!.statusCode >= 200 && response.response!.statusCode <= 300 {
completion("success")
}else {
completion("failed")
}
}
here newPassword is string. from there I created the Data object. You have to convert your Custom class object to Data object.

Post method request Alamofire

I'm using Swift 3 and Alamofire 4.0.
I want to create similar Alamofire POST request as Postman request shown in screenshot:
I've tried with these lines of code:
var parameters: [String: Any] = [
"client_id" : "xxxxxx",
"client_secret" : "xxxxx",
"device_token" : "xxxx",
"fullname" : "xxxxx",
"gender": "xxx"
]
Alamofire.request(url, method: .post, parameters: parameters).responseJSON { response in
print(response)
}
But I got this error:
How to implement POST request with Body as form-data using Alamofire in Swift 3?
Swift 3.0 - Alamofire - Working code for multipart form data upload *
// Parameters
let params: [String : String] =
["UserId" : "\(userID)",
"FirstName" : firstNameTF.text!,
"LastName" : lastNameTF.text!,
"Email" : emailTF.text!
]
// And upload
Alamofire.upload(
multipartFormData: { multipartFormData in
for (key, value) in params
{
multipartFormData.append((value.data(using: .utf8))!, withName: key)
}
},
to: url,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
upload.uploadProgress(queue: DispatchQueue(label: "uploadQueue"), closure: { (progress) in
})
case .failure(let encodingError):
print(encodingError)
}
}
)
Let me know if you still have issues with it.
after too much try I have succeded so try this
override func viewDidLoad() {
super.viewDidLoad()
let parameters: Parameters = ["client_id": "1","user_token":"xxxxxxxx"]
// Do any additional setup after loading the view, typically from a nib.
let url = "http://xxxxxxxxxxx/index.php/Web_api/get_client_profile"
//let timeParameter = self.getLastTimeStamp()
self.request = Alamofire.request(url, method: .post, parameters:parameters)
if let request = request as? DataRequest {
request.responseString { response in
//PKHUD.sharedHUD.hide()
do{
let dictionary = try JSONSerialization.jsonObject(with: response.data!, options: JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
print(dictionary)
}catch{
}
}
}
}
var request: Alamofire.Request? {
didSet {
//oldValue?.cancel()
}
}
You can post a request using Alamofire.
let url = ""
let headers = [ "Content-Type" : "application/json"]
let para : Parameters = [ "data" : JSONObject]
Alamofire.request(url, method: .post, parameters: para, encoding: JSONEncoding.default, headers : headers)
.responseJSON { response in
print(response)
print(response.result)
}
Nothing to worry about.
Alamofire request method not changed so much(For Swift 3.0) if in case you know how to do that in Swift 2.0/2.2. If you understand the old method then you can easily understand this one also. Now lets take a closer look on the following boilerplate -
Alamofire.request(apiToHit, method: .post, parameters: parametersObject, encoding: JSONEncoding.default, headers: headerForApi).responseJSON { response in switch response.result{
case .success(_):
if let receivedData: Any = response.result.value{
if let statusCode: Int = response.response?.statusCode {
//Got the status code and data. Do your data pursing task from here.
}
}else{
//Response data is not valid, So do some other calculations here
}
case .failure(_):
//Api request process failed. Check for errors here.
}
Now here in my case -
apiToHit //Your api url string
.post //Method of the request. You can change this method as per you need like .post, .get, .put, .delete etc.
parametersObject // Parameters needed for this particular api. Same in case you are sending the "body" on postman etc. Remember this parameters should be in form of [String: Any]. If you don't need this then you can just pass nil.
JSONEncoding.default //This the encoding process. In my case I am setting this as .default which is expected here. You can change this to .prettyPrinted also if you need.
headerForApi //This is the header which you want to send while you are requesting the api. In my case it is in [String: String] format. If you don't need this then you can just pass nil.
.responseJSON //Expecting the response as in JSON format. You can also change this as you need.
Now, in my request I am using Switch inside the request closure to check the result like response in switch response.result{.
Inside case .success(_): case I am also checking for result data and http status code as well like this
if let receivedData: Any = response.result.value{
if let statusCode: Int = response.response?.statusCode {
}
}
Hope this helped. Thanks.
class func alamofireMethod(methods: Alamofire.HTTPMethod , url : URLConvertible , parameters : [String : Any],need_flag_inside : Bool = false, paramJson : Bool = true ,need_loader : Bool = true,Header: [String: String],handler:#escaping CompletionHandler,errorhandler : #escaping ErrorHandler)
{
if NetworkController.sharedInstance.checkNetworkStatus()
{
var alamofireManager : Alamofire.SessionManager?
var hed = Header
if let tok = UserDefaults.standard.value(forKey: "TOKEN") as? String {
hed = ["Authorization":"Bearer \(tok)"]
}
if need_loader {
// DELEGATE.showLoader()
}
var UrlFinal = ""
do
{
try UrlFinal = baseURL + url.asURL().absoluteString
}
catch{}
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForResource = 25
configuration.timeoutIntervalForRequest = 25
configuration.httpAdditionalHeaders = hed
alamofireManager = Alamofire.SessionManager(configuration: configuration)
alamofireManager = Alamofire.SessionManager.default
let json = JSON(parameters)
guard let jsonDict = json.dictionaryObject else {
return
}
var jsonData = Data()
do {
jsonData = try JSONSerialization.data(withJSONObject: jsonDict, options: [])
} catch {
//handle error
print(error)
}
var request = URLRequest(url: URL(string: UrlFinal)!)
request.httpMethod = methods.rawValue
if methods == .post || methods == .put
{
//check here
if paramJson {
hed["Content-Type"] = "application/json"
request.httpBody = jsonData
}else{
let postString = self.getPostString(params: parameters)
request.httpBody = postString.data(using: .utf8)
}
}
request.allHTTPHeaderFields = hed
Alamofire.request(request).responseJSON(queue: nil, options: JSONSerialization.ReadingOptions.allowFragments) { (response) in
print(parameters)
print(UrlFinal)
print(hed)
// DELEGATE.hideLoader()
if response.result.isSuccess
{
print(response)
handler(response.result.value! as AnyObject)
}
else if response.response?.statusCode == 401
{
// DELEGATE.redirectToLogin()
// DELEGATE.showToast(message: "Token Expired")
}
else{
// DELEGATE.showToast(message: default_failure)
errorhandler(response.result.error! as NSError)
print(response.result.error as Any)
}
}
}else{
// DELEGATE.showToast(message: "Please check your internet connection.")
}
}
Alomofire With Post and Put Method In swift

Alamofire POST request not working

let requestDictionary : [String: AnyObject] = [
"sm_username" : name as AnyObject,
"sm_password" : pass as AnyObject
]
let headers = [
"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
"Content-Type": "application/x-www-form-urlencoded",
"Krikor": "Krikor"
]
Alamofire.request(baseURL+"login", method: .post, parameters: requestDictionary, encoding: JSONEncoding(options: []),headers: headers
).responseJSON{ response in
debugPrint(response)
print("krirkrkdkd")
print(response)
}
So basically, the headers are not being passed. Neither encoded parameters. Why? And how to fix?
Kiikor,
Here is a working example of a alamofire request in swift, including the encoding.
func files_download(sourcePath: String) {
let defaults = UserDefaults.standard
if let name = defaults.string(forKey: "dropBoxAuth")
{
token2Save = name
}
var headers:HTTPHeaders!
let subPart: Dictionary = ["path":sourcePath]
do {
let data = try JSONSerialization.data(withJSONObject: subPart, options: [])
let dataString = String(data: data, encoding: .utf8)
headers = ["Authorization": "Bearer " + token2Save, "Dropbox-API-Arg": dataString!]
} catch {
print("error")
}
Alamofire.request("https://content.dropboxapi.com/2/files/download", method: .post, encoding: JSONEncoding.init(options: []), headers: headers).responseData(completionHandler: {feedback in
guard feedback.result.value != nil else {
print("Error: did not receive data", print("request \(request) feedback \(feedback)"))
return
}
guard feedback.result.error == nil else {
print("error calling POST on list_folder")
print(feedback.result.error)
return
}
if let JSON = feedback.result.value {
let dataString = String(data: JSON, encoding: .utf8)
}
if let IMAGE = feedback.result.value {
sharedDataAccess.fnData(index2seek: 0, fnData: feedback.result.value! as Data)
NotificationCenter.default.post(name: Notification.Name("nextACtion"), object: nil, userInfo: nil)
}
})

Resources