how to avoid Alamofire change parameters automatically? - ios

It's strange when i see in Xcode console, the output of URL parameters are not the same as i inputted using Alamofire,
parameters' sequence changed
and extra numbers "25" added into parameter "key",
Pls see following original code:
let weatherURL="http://open.weather.com.cn/data/"
let params=["areaid":"\(areaid)","type":"forecast_v","date":"\(time)","appid":"1eb583","key":"\(URLEncodeKey)"]
Alamofire.request(.GET, weatherURL, parameters: params)
.responseJSON { (request, response, json, error) in
if((error) != nil){
println(request)
println("Error:\(error)")
}else{
println(request)
println(json)
}
}
the output of URL in console:
key:2v7eK8AlzynX%2BuLBgw7DU74f8S0%3D
NSMutableURLRequest: 0x7fe3f14a1bf0 { URL: http://open.weather.com.cn/data/?appid=1eb583&areaid=101020900&date=201507211626&key=2v7eK8AlzynX%252BuLBgw7DU74f8S0%253D&type=forecast_v }
These two problems caused error:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Invalid value around character 0.)
Thus i can't get the data from API. But when the URL is corrected from above two problems by hand, means URL:
http://open.weather.com.cn/data/?areaid=101020900&type=forecast_v&date=201507211626&appid=1eb583&key=2v7eK8AlzynX%2BuLBgw7DU74f8S0%3D
change the parameters sequence as the same in constant "params",
and remove extra "25".
Then it works, i can see the responding data from API in web browser.
So, please, what problems i ignored in my code?
Thank you!

You say that you are seeing the following on the console:
key:2v7eK8AlzynX%2BuLBgw7DU74f8S0%3D
You're not showing us how this key value was generated, but that's very strange, because that string is percent escaped, and it shouldn't be. If you remove the percent escapes, you see something like
key:2v7eK8AlzynX+uLBgw7DU74f8S0=
And that is a well formed base64 string.
The thing is, if you're using Alamofire, you should not be percent escaping it (Alamofire does that for you). In fact, that's why you're seeing the extra "25", because it's percent escaping your key string a second time, replacing the % characters with %25.
Bottom line, find out why the key is already percent escaped, and prevent that from happening. (Or, remove the percent escapes with stringByReplacingPercentEscapesUsingEncoding before adding it to the dictionary; but it's better to prevent the percent escaping rather than adding and then replacing the percent escapes.) If you pass it the 2v7eK8AlzynX+uLBgw7DU74f8S0= value in the parameters dictionary, everything should be fine.
Regarding of the parameters collection: The parameters is a dictionary, and unlike arrays, dictionaries are not ordered collections, and they won't preserve the order you specify the keys. Fortunately, the parameters in HTTP requests in standard web servers are not order-specific, either, so this is not an issue.

Related

iOS: Almofire PUT and DELETE Call is not working with Params in Swift

I am trying to Put and Delete data through Almofire Library but facing issue regarding parameters. Params are missing, following are the error:
Response JSON data = {
data = "<null>";
issuccess = 0;
msg = "{'car_id': [ErrorDetail(string='This field is required.', code='required')], 'car_brand_id': [ErrorDetail(string='This field is required.', code='required')], 'last_oil_change': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY-MM-DD.', code='invalid')]} with error { Custom error message. }";
}
I am using the following code:
let params : [String : String] = ["brand_model_id": String(car_model_id), "oil_brand_id": String(oil_brand_id), "car_mileage": edCurrentMilage.text!, "car_modelyear": edVehicleModelYear.text!, "last_oil_change": edLastOilChange.text!]
Alamofire.request(Constants.APIURL + Constants.APIPOSTCARDATA ,method:.put, parameters: params, encoding: JSONEncoding.default, headers: header).responseJSON { [self] response in
guard response.result.isSuccess,
let value = response.result.value else {
print("Error while fetching tags: \(String(describing: response.result.error))")
self.hideIndicator()
// self.btn_submit_outlet.isEnabled = true
// completion(nil)
return
}
print(value)
let json = JSON.init(value as! NSDictionary)
print(json)
let code = json["issuccess"].boolValue
if(code)
{
self.hideIndicator()
Commons.showAlert(title: "Alert", error: "Data has been added.", VC: self)
}
else
{
self.hideIndicator()
Commons.showAlert(title: String.localizedStringWithFormat(NSLocalizedString("Alert", comment: "")), error: String.localizedStringWithFormat(NSLocalizedString("Something went wrong.", comment: "")), VC: self)
}
}
Above mention code is used for the PUT call Please help. Thanks in advance.
It's not against you particularly, BUT, it's something that is lacking a lot in this kind of questions.
Usually, by reading output error, in our case the server response we might, and I insist on "might", find the solution. But it's not always the case, sometimes error message is too generic, or pointing to the wrong direction. Here, error is saying about missing "car_id" param, but according to you it's not needed, so it's misleading (if we believe your saying).
Another usually good hint, is saying that "It's working on Android", "It's working in Postman", "It's working with a cURL command".
Usually, when this happen, I'm asking myself:
Why the author doesn't show the Postman, Android code, cURL command that would allow people knowing both tools/languages/platforms to spot a difference that could be the mistake.
Let's be honest, that would be easier, no? You might have quickly the right solution/fix, no? It's better than trying to guess battling agains the server response, no?
Now...
You are using Alamofire AND Postman. What if I told you that might be enough for you?
Quick trivia:
Did you know that Postman can generate code for the request?
It can even generate Swift Code for your request using URLSession? It's not "beautiful", "swifty" Swift code, but it's enough to spot difference and find why it's working on Postman and not in your code.
It can also generate cURL command? If you don't know about cURL a quick explanation would be "command line tool to make web request with params etc in Terminal.app/Bash/Shell, ie: it's basic and usually known by a lot of developers, so even if you only speak JavaScript, Java, etc, it's often like a "common language"
How? Even when I say that in comments, people don't even try to search for it... Let's find it with your favorite Search Engine, which should lead you to this tutorial/blog post. And tadaaa!
Did you know that AlamoFire can print request as cURL equivalent? It's stated here.
So in your case, what about asking Alamofire and Postman to generate cURL command and compare?
Then, you might want to change the parameters of the request, or even the parameters of the method request(_:method:parameters:encoding:headers:).
Why I am saying this?
Because if you don't give enough informations, there will be a delay between someone asking for more info/details in comment and yourself responding to them. Also, different commenters will ask for different questions, since debugging is a skill and causes might be multiples, we might ask different things, and only one will be relevant in the end to your issue, but we can't guess which one until then.
Because spotting difference is easier and might attract quicker response.
Now that you know about POSTMAN and Alamofire and cURL, you might even find yourself the solution. Even quicker than making a question on SO! Be your own hero!
In the end, only an "attractive" question will have good answers, so give as much info as possible, don't hold them (parameters sent, equivalent android code, screenshot at least of the Postman, but know that you know about the cURL generation code). Of course, keep your private token etc, obfuscate them a little, but still, you might have watch enough TV shows/movies where holding info is bad for the main characters, why repeating that mistake here?
As the error message says: Date has wrong format. Use one of these formats instead: YYYY-MM-DD.
Please check "last_oil_change" field. The value is from edLastOilChange.text. Does edLastOilChange.text meet the required format?

Extra slash ( \ ) getting added when string (with unicode character) added to a dictionary

I am facing the following issue:
In my app, the user can enter special characters (like emojis) in a textfield also. So, while sending this entered text to server in request body, I am converting it using the following code:
func emojiToUTF8()->String
{
let data = self.data(using: .nonLossyASCII, allowLossyConversion: true)
let emoji = String.init(data: data!, encoding: .utf8)
return emoji ?? self
}
For instance, if I enter the text "☺️", it gets converted into "\u263a\ufe0f" using the above method. Things are fine till here.
The problem occurs when I add this to a dictionary for sending it as a request parameter to the server. Code i'm using:
var parameters = [String:String]()
parameters["feedback"] = feedBackTxt
print("Parameters:",parameters) /// output: ["feedback": "\\u263a\\ufe0f"]
So, the problem here is that an extra slash is getting appended before each slash due to char escaping. I checked the created dictionary value as well. It shows double slash there also. How do I avoid this? Why is this happening when I am simply creating a dictionary with a string? This is causing issue at server end.
I have tried a couple of things, but none of them seem to work.
Your problem is that you're double-encoding.
You're taking a string, converting it to ASCII, then re-parsing it as UTF8 and then encoding that (probably) as JSON, which is UTF8. In the process, the backslashes are being escaped by your second encoder.
The best solution to this is to rework your server to accept UTF8. However, if you can't do that, you need to ensure you encode this string just one time, in ASCII.
In short, you should get rid of emojiToUTF8 and ensure that your parameters processor encodes the way your server requires (which apparently is ASCII and not UTF8).

What does implementation-defined value in FileAPI/unicodeBlobURL mean?

In https://w3c.github.io/FileAPI/#unicodeBlobURL:
The Serialization of a Blob URL is the value returned by the following algorithm, which is invoked by URL.createObjectURL():
Let result be the empty string. Append the string "blob" (that is, the Unicode code point sequence U+0062, U+006C, U+006F, U+0062) to result.
Append the ":" (U+003A COLON) character to result.
Let settings be the current settings object
Let origin be settings’s origin.
Let serialized be the ASCII serialization of origin.
If serialized is "null", set it to an implementation-defined value.
...
What is this implementation-defined value?
UPDATE: I try to implement this on jsdom, so want to figure out what should I do.
As an implementer, It's up to you, as long as it's not a valid origin.
Most browsers (tested in FF, chrome and Safari) seems to set it to 'null'.
We can check it thanks to the sand-boxed iframe of stacksnippet.
console.log(URL.createObjectURL(new Blob([])));

geting error with Dictionary

let parameter : Dictionary<String,AnyObject> = ["action":"add-playlist-item","playlist_id":self.dictPlayList.objectForKey("ID")!,"kod_id":arrayOfID]
error
["action": add-playlist-item, "playlist_id": 166, "kod_id": <_TtCs21_SwiftDeferredNSArray 0x7c615620>(
21,
18
)
]
_TtCs21_SwiftDeferredNSArray 0x7c615620 what does this error mean??
Array is a value type and it's not an object, but a struct. So it doesn't conform to AnyObject protocol. Use Any instead of AnyObject. See more details here and here.
Check that you are using JSON parameter encoding, not URL encoding.
You may be having the same problem I was having. I was seeing <_TtCs21_SwiftDeferredNSArray 0x7c615620> appear in my requests too. When I changed to JSON encoding, everything worked. I don't think a dictionary structure like that can be properly URL encoded. I'm not sure how you're actually making the request or I would post code.

RestKit path pattern for comma separated dynamic arguments

I am using RestKit, i have send a single GET request to get a bulk data to a URL like this
api/exemptions?ids=203,1985,21855
What path pattern can be set for this in RestKit response descriptor?
I know for predefined number of dynamic argument we can use something like this #"/api/sms/confirmation/:arg1/:arg2"
but above mentioned case is new for me.
EDIT
I found that parameter argument in
[[RKObjectManager sharedManager] getObjectsAtPath:path parameters:nil
will do the job, but it requires a dictionary so i am giving it an example dictionary NSDictionary *args = #{ #"ids" : #[#"1",#"2",#"3",#"4"] };
when executed this encoded url is generated
http://../api/exemptions?&ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3&ids%5B%5D=4
"ids" key is repeating, what is going wrong here.
EDIT # 2
URL encoding problem is solved, but the main problem still persists, path pattern is not matching on response, I am using this path pattern currently
pathPattern:#"/api/exemptions?&ids"
for this url /api/exemptions?ids=203,1985,21855
i have also tried pathPattern:#"/api/exemptions?&ids="
Please help, This is becoming huge pain.
Based on your sample code and response, have you tried:
NSDictionary *args = #{ #"ids": [#[#"1", #"2"] componentsJoinedByString: #","] };
This looks like it would encode with the desired value, since the joining leads to a dictionary value of #{ #"ids": #"1,2" }.

Resources