Strange error with underscore in Alamofire parameters - ios

I am trying to pass username, password and grant_type values as a POST request.
Currently I have an array set up like :
params = [
"grant_type": "password",
"password": password,
"username": user
]
When they get passed to my alamofire POST request though, and I log them out they look like this:
params = {
"grant_type" = password;
password = pas;
username = user;
}
With pas and user being my inputted values.
This results in a 400 error from my server, I suspect its because grant_type is being read as having quotes for some reason?
This is how im making my POST request:
networking.makePostRequest(Constants.loginUrl, params: loginParams) { response, json in
print("response")
print(response)
print("json")
print(json)
}
With the actual POST request function looking like this:
unc makePostRequest(url : String, params : AnyObject, completionHandler: (httpResponse: NSHTTPURLResponse, responseObject:JSON?) -> ()) -> Request? {
print("params = \(params)")
return Alamofire.request(.POST, url, parameters: params as? [String : AnyObject], encoding: .JSON)
.responseJSON { _, response, result in completionHandler(
httpResponse: response!,
responseObject:
{
var json: JSON?
switch result {
case .Success:
if let data: AnyObject = result.data
{
json = JSON(data)
}
return json
case .Failure(_, let error):
print(error)
}
return json
}()
)
}
}

Related

Replicating post method in Postman with parameters and body-raw into Alamofire

I'm having a problem on using Alamofire. When I try to post a request using a generic parameters like ["name":"John", "age":"27"] it always succeeds. But, when I try to use a web service that requires parameters and a body-raw for a base64 string I'm not able to get a successful response from the server. Though it succeeds when I use Postman. Does anyone knows how to do this on Alamofire 4? Here is the screenshot of my postman.
Thank you!
#nathan- this is the code that I used. I just assumed that the base64String inside the "let paramsDict" has a key value named "data" though it doesn't have a key name in postman.
let urlString = ApiManager.sharedInstance.formsURL + ApiManager.sharedInstance.mobileFormsImageUpload
let paramsDict = ["token": token, "fileID":"2", "filename":"images.png", "data": base64String] as [String : Any]
Alamofire.request(urlString, method: .post, parameters: paramsDict, encoding: URLEncoding.httpBody, headers: [:])
.responseJSON{ response in
switch response.result {
case .success(let data):
debugPrint("SUCCESS")
case .failure(let error):
debugPrint("Request Error")
}
}
I already figured it out. It needs a custom encoding to make it work. All the parameters must be inlined with the url so the base64 string inside the parameter is the only to be encoded. Here is the code that I used.
struct CustomPostEncoding: ParameterEncoding {
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var request = try URLEncoding().encode(urlRequest, with: parameters)
let base64 = parameters?["data"] as! String
let finalBase64Format = "\"" + base64 + "\""
let postData = NSData(data: finalBase64Format.data(using: String.Encoding.utf8)!)
request.httpBody = postData as Data
return request
}
}
func uploadImageBase64(){
let jpegCompressionQuality: CGFloat = 0.9 // Set this to whatever suits your purpose
if let base64String = UIImageJPEGRepresentation(testIMG, jpegCompressionQuality)?.base64EncodedString() {
var token = String()
if let data = UserDefaults.standard.data(forKey: "userProfile"),
let user = NSKeyedUnarchiver.unarchiveObject(with: data) as? UserProfile{
token = user.token
} else {
print("There is an issue")
}
let headers = [
"content-Type": "application/json"
]
let urlString = "http://localhost/FormsService.svc/Getbase64?filename=test.png&fileID=1151&token=80977580xxx"
let paramsDict = ["data": base64String] as [String : Any]
Alamofire.request(urlString, method: .post, parameters: paramsDict, encoding: CustomPostEncoding(), headers: headers)
.responseJSON{ response in
print("response JSON \(response.result)")
}
.response{ response in
print("RESPONSE \(response)")
}
}
}

I have a url which posts some data to the server. How do i convert it to alamofire post request method with all parameters mentioned in URL

let url = "(InsertAsset)?customerID=(vmanagerappDelegate.cust_Id!)&assetTag=(self.txt_AssetTag.text! as String)&modelID=(modelObject)&statusID=(statusObject)&serial=(self.txt_Serial.text! as String)&assetName=(self.txt_AssetName.text! as String)&purchaseDate=(selectedPurchaseDate)&supplierID=(supplierObject)&purchaseCost=(purchaseCostObject)&warranty=(self.txt_Warranty.text! as String)&notes=(notesObject)&locationID=(locationObject)&ownerID=(ownerObject)&addUserID=(vmanagerappDelegate.userId as String)&saleEndDate=(self.txt_Sale_End_Date.text! as String)&softwareMaintainenceEndDate=(self.txt_Software_Maintainence_End_Date.text! as String)&supportEndDate=(self.txt_Support_End_Date.text! as String)&MacAddress=(self.txt_Mac_Address.text! as String)&sitekey=testing"
Hi you can create dictionary like following to send parameter as dictionary in Alamofire :
var dicParam = Dictionary<String,AnyObject>()
dicParam[“customerID”] = vmanagerappDelegate.cust_Id!
dicParam[“assetTag”] = self.txt_AssetTag.text! as String
dicParam["modelID"] = modelObject
In Alamofire pass above dictionary as parameters along with your URL like following :
Alamofire.request("Your URL", method: .post, parameters: dicParam, encoding: URLEncoding(destination: .queryString), headers: nil).responseJSON {
response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
try creating a dicitonary
let params:Dictionary<String, AnyObject> = ["customerID":vmanagerappDelegate.cust_Id!,"assetTag":self.txt_AssetTag.text,"modelID":modelObject] //similarly add all params to Dict
if you want to add some headers create dicitonary Header for them too and pass in Alamofire.request(.POST,url,parameters: params,headers:Header,encoding: .JSON)
a example for post request
func remotePOSTServiceWithParameters(urlString : String , params : Dictionary<String, AnyObject> , callback:(data: Dictionary<String, AnyObject>?, error: NSError? ) -> Void) {
print("Request POST URL:\(urlString) PARAMS:\(params)")
Alamofire.request(.POST,urlString,parameters: params,encoding: .JSON)
.validate()
.responseJSON {
response in
guard response.result.error == nil else {
print("Error for POST :\(urlString):\(response.result.error!)")
//
callback(data: nil , error: response.result.error! )
return
}
if let value = response.result.value {
print("JSON: \(value)")
if let result = value as? Dictionary<String, AnyObject> {
print("Response for POST :\(urlString):\(value)")
callback(data:result , error: nil )
}
}
}
}

Alamofire response not matching request

I am having an issue when making a POST request to my API via Alamofire, GETs work without issue, however whenever I make a POST when I check the response I get the results of the last GET.
import Alamofire
import SwiftyJSON
class NetworkManager {
static let sharedInstace = NetworkManager()
let defaultManager: Alamofire.Manager = {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"homestead.app": .DisableEvaluation
]
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
return Alamofire.Manager(
configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
}()
}
internal class ApiHelper {
/**
Get data from a target URL and return JSON data to be parsed
- parameter targetURL: URL to pull data from
- parameter success: return data to the calling function
- parameter failure: return an error message to the calling function
*/
private func getDataFromAPI(targetURL: String, success:(JSONData: JSON) -> (), failure:(message: String) -> ()) {
NetworkManager.sharedInstace.defaultManager.request(.GET, targetURL).responseJSON { response in
print(response.result)
switch response.result {
case .Success:
if let jsonRaw = response.result.value {
let json = JSON(jsonRaw)
success(JSONData: json)
}
case .Failure(let error):
print(error.localizedDescription)
failure(message: error.localizedDescription)
}
}
}
/**
Post data to the target URL and return errors as JSON data to be parsed
- parameter targetURL: URL to post to
- parameter parameters: JSON data to post
- parameter success: return success message to the calling function
- parameter failure: return JSON data to the calling function with server error
*/
private func postDataToAPI(targetURL: String, parameters: [String : AnyObject], success:() -> (), failure:(JSONData: JSON) -> ()) {
NetworkManager.sharedInstace.defaultManager.request(.POST, targetURL, parameters: parameters, encoding: .JSON).responseJSON { response in
debugPrint(response)
success()
}
}
/**
Post an updated profile to the API
- parameter parameters: JSON data to be posted
- parameter success: success callback
- parameter failure: JSON data of serverError
*/
internal func postUpdateRequest(parameters: [String : AnyObject], success:() -> (), failure:(JSONData: JSON) -> ()) {
let url = "https://homestead.app/profile/a/update"
postDataToAPI(url, parameters: parameters, success: {
success()
}, failure: { JSONData in
failure(JSONData: JSONData)
})
}
/**
Get all states from the API
- parameter success: JSON data of all states
- parameter failure: failure message
*/
internal func getAllStates(success:(JSONData: JSON) -> (), failure:(message: String) -> ()) {
let url = "https://homestead.app/api/state/all"
getDataFromAPI(url, success:
{ JSONData in
success(JSONData: JSONData)
}, failure: { message in
failure(message: message)
})
}
}
let api = ApiHelper()
api.getAllStates({ JSONdata in
print(JSONdata)
let params: [String : AnyObject] = ["name" : "Bob"]
api.postUpdateRequest(params, success: { JSONdata in
print("Success")
}, failure: { message in
print("Message")
})
}, failure: { message in
print(message)
})
My code first gets the list of states and then posts an updated user profile. My issue is in that when I get the response for that updated user profile, it includes the response from the earlier GET request that had already been completed. The POST goes through and the changes are made in the web services, but I have no indications in my response object.
I have confirmed the server does not return the list of states when making a POST request, it returns below when called manually from the browser:
{
"success": "Changes saved!"
}
I'm at a loss on why I am getting a response from an earlier request from my POST. Any thoughts?
I figured this out. It turned out I had to add "X-Requested-With": "XMLHttpRequest" to the requests header:
configuration.HTTPAdditionalHeaders = [
"X-Requested-With": "XMLHttpRequest"
]
Now I am getting the responses correctly from the server.

Using a value from Alamofire request outside the function

I can't seem to figure this one out: I am trying to get an error from my server (in JSON) using an Alamofire request, but I cannot get the value outside the function.
This is the implementation of my function:
func alamoRequest(username : String, email: String, password: String, facebook: String, completionHandler : (String?) -> Void) {
var jsonValue : JSON?
let URL = "http://someurl.com/login.php"
let requestParameters = ["username" : username, "email" : email, "password" : password, "facebook" : facebook, "date": NSNull()];
var jsonString : String = String()
Alamofire.request(.GET, URL, parameters: requestParameters).validate().responseJSON {
response in
switch response.result {
case .Success:
if let value = response.result.value {
jsonValue = JSON(value)
jsonString = jsonValue!["error"].stringValue
print("Value in implementation is: \(jsonString)")
}
case .Failure(let error):
print(error)
}
}
completionHandler(jsonString)
}
And here is how I call it:
logic.alamoRequest(usernameField.text!, email: emailField.text!, password: passwordField.text!, facebook: "false") {
json in
jsonString = json!
}
alamoRequest = jsonString
print("Value in call is: \(alamoRequest))
But the output is always like this:
Value from call is:
Value in implementation is: Email already exists
How can I "return" something from the function or wait for it to execute without blocking the UI?
Your operation is async, the way of waiting for the completion is just using closures, you're trying to return the value outside the closure so the value is not retrieved yet!! and it's the cause of your empty value, you can "throw" the completionHandler inside your closure like in the following example :
func alamoRequest(username : String, email: String, password: String, facebook: String, completionHandler : (String?) -> Void) {
var jsonValue : JSON?
let URL = "http://someurl.com/login.php"
let requestParameters = ["username" : username, "email" : email, "password" : password, "facebook" : facebook, "date": NSNull()];
var jsonString : String = String()
Alamofire.request(.GET, URL, parameters: requestParameters).validate().responseJSON {
response in
switch response.result {
case .Success:
if let value = response.result.value {
jsonValue = JSON(value)
jsonString = jsonValue!["error"].stringValue
print("Value in implementation is: \(jsonString)")
completionHandler(jsonString)
}
case .Failure(let error):
print(error)
}
}
}
Nevertheless, in the above way the only way of you don't know if exist some error in the request because your completionHandler is called only inside the .Success case, if you want you can call it always, after the last case of the enum.
Alamofire.request(.GET, URL, parameters: requestParameters).validate().responseJSON {
response in
switch response.result {
case .Success:
if let value = response.result.value {
jsonValue = JSON(value)
jsonString = jsonValue!["error"].stringValue
print("Value in implementation is: \(jsonString)")
}
case .Failure(let error):
jsonString = nil
}
completionHandler(jsonString)
}
}
And if the jsonString is nil some error has ocurred, but again you don't know anything about the error, then you have two options :
Change your closure to always return the jsonString and the error too
Encapsulating the error into a throwable closure.
The first case is very simple, just change your closure and always have the error returned, if it's nil then no error ocurred.
The other option I think is the better, like in the following example:
func alamoRequest(username : String, email: String, password: String, facebook: String,
completion: (inner: () throws -> String) -> ()) {
var jsonValue : JSON?
let URL = "http://someurl.com/login.php"
let requestParameters = ["username" : username, "email" : email, "password" : password, "facebook" : facebook, "date": NSNull()];
var jsonString : String = String()
Alamofire.request(.GET, URL, parameters: requestParameters).validate().responseJSON {
response in
switch response.result {
case .Success:
if let value = response.result.value {
jsonValue = JSON(value)
jsonString = jsonValue!["error"].stringValue
print("Value in implementation is: \(jsonString)")
completionHandler(inner: { return jsonString })
}
case .Failure(let error):
completionHandler(inner: { return error })
}
}
}
And then you can call it like in the following way:
self.alamoRequest(usernameField.text!, email: emailField.text!, password: passwordField.text!, facebook: "false") { (inner: () throws -> String) -> Void in
do {
let result = try inner()
} catch let error {
print(error)
}
}
The trick is that the alamoRequest function takes an additional closure called 'inner' of the type () throws -> String. This closure will either provide the result of the computation, or it will throw. The closure itself is being constructed during the computation by one of two means:
In case of an error: inner: {throw error}
In case of success: inner: {return result}
I strongly recommend you an excellent article about using try/catch in async calls Using try / catch in Swift with asynchronous closures
I hope this help you.

Alomofire POST request in swift

I am using the following code in my swift 2.0 project. I cannot add Alamofire.request though I added "import Alamofire". I have to create object of Alamofire and then access through it.
This is how I create the object :
let manager = Alamofire.Manager.sharedInstance
manager.request(NSURLRequest(URL: NSURL(string: "http://httpbin.org/get")!))
let parameters = ["foo": "bar"]
manager.request(.POST, "url", parameters: parameters)
.responseJSON { request, response, json, error in
print("request: \(request)")
}
I am new to both Alamofire and swift. Can anybody tell how can I get response from the above code in a completion handler and why I cannot use Alamofire.request instead of manager.request.
Please see my Post method and Hope It helps
Post Method:
/**
** POST Method for calling API
* Services gateway
* Method get response from server
* #parameter -> requestObject: request josn object ,apiName: api endpoint
* #returm -> void
* #compilationHandler -> success: status of api, response: respose from server, error: error handling
**/
static func getDataWithObject( requestObject: NSDictionary, apiName : NSString,
completionHandler:
(success : Bool, response : NSDictionary, error : ErrorType?) -> Void) {
// Make Url
let url = NSURL(string: apiName as String)
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
//request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// Call the method to request and wait for the response
// #param ->
// #return ->
Alamofire.request(.POST, url!, parameters:requestObject as? [String : AnyObject], encoding: .JSON)
.responseJSON {responseRequest, responseResponse, responseResult in
// Switch for Success or Error
switch responseResult {
// If the API return succesfull response
case .Success(let data):
let data_ar = data as! NSDictionary
print(data_ar)
// Get the Status if 0 then error if 1 then succes
// From our server side
if let str = data_ar.valueForKey("OK") as? Bool {
// Check if the status is OK and no error from
// our server side
if ( str ) {
print("Response from Server %#", data_ar)
// Cast the response and pss to handler
// To notify
completionHandler(success: true, response:data_ar
, error:responseResult.error )
} else {
print("Error from Our Server %#", data_ar)
let str = data_ar.valueForKey("message") as! NSString
self.showAlertView(str, title: "Error From Server")
}
}
case .Failure(let data, let error):
print("Request failed with error: \(error)")
print(data)
print((error as! NSError).localizedDescription)
self.showAlertView((error as! NSError).localizedDescription, title: "Error From Server")
}
}
}
Request not always in JSON please check your request :
Following are examples to use Alamofire with the Swift 2 :
GET - JSON
Alamofire.request(.GET, "http://api.androidhive.info/contacts/", parameters: nil, encoding: .JSON, headers: nil).responseJSON { (req, res, json) -> Void in
print("\(res?.allHeaderFields)")
print("\(json.value!)")
}
POST - without JSON
Alamofire.request(.POST, "http://httpbin.org/get", parameters: ["foo": "bar"], encoding: .URL, headers: nil).response { (req, res, data, error) -> Void in
print(res)
print(data)
let dataString = NSString(data: data!, encoding:NSUTF8StringEncoding)
print(dataString)
}

Resources