URL Encode Alamofire GET params with SwiftyJSON - ios

I am trying to have Alamofire send the following parameter in a GET request but it's sending gibberish:
filters={"$and":[{"name":{"$bw":"duke"},"country":"gb"}]}
//www.example.com/example?filters={"$and":[{"name":{"$bw":"duke"},"country":"gb"}]}
//Obviously URL encoded
This is my code:
let jsonObject = ["$and":[["name":["$bw":string], "country":"gb"]]]
let json = JSON(jsonObject)
print(json)
outputs
{
"$and" : [
{
"name" : {
"$bw" : "duke"
},
"country" : "gb"
}
]
}
This is my params request:
let params = ["filters" : json.rawValue, "limit":"1", "KEY":"my_key"]
This is what AlamoFire is sending:
KEY=my_key&
filters[$and][][country]=gb&
filters[$and][][name][$bw]=duke&
limit=1
As you can see the filter parameter is a complete mess. What am I doing wrong?

By default Alamofire encodes the parameters using Parameter List in the POST body. Try changing the encoding to JSON. This way Alamofire will serialize the dictionary as a JSON string as you expect:
let parameters = [
"foo": [1,2,3],
"bar": [
"baz": "qux"
]
]
Alamofire.request(.POST, "http://httpbin.org/post", parameters: parameters, encoding: .JSON)
// HTTP body: {"foo": [1, 2, 3], "bar": {"baz": "qux"}}
Or using your code:
let string = "duke"
let jsonObject = ["$and":[["name":["$bw":string], "country":"gb"]]]
let json = JSON(jsonObject)
let params = ["filters" : json.rawValue, "limit":"1", "KEY":"my_key"]
Alamofire.request(.POST, "http://httpbin.org/post", parameters: params, encoding: .JSON)
.responseString(encoding: NSUTF8StringEncoding) { request, response, content, error in
NSLog("Request: %# - %#\n%#", request.HTTPMethod!, request.URL!, request.HTTPBody.map { body in NSString(data: body, encoding: NSUTF8StringEncoding) ?? "" } ?? "")
if let response = response {
NSLog("Response: %#\n%#", response, content ?? "")
}
}
Gets the output:
Request: POST - http://httpbin.org/post
{"filters":{"$and":[{"name":{"$bw":"duke"},"country":"gb"}]},"limit":"1","KEY":"my_key"}
EDIT: URL-Encoded JSON in the GET parameters
If you want to send a URL-Encoded JSON in the GET parameters you have to generate first the JSON string and then pass it as a string in your parameters dictionary:
SWIFT 1
let string = "duke"
let jsonObject = ["$and":[["name":["$bw":string], "country":"gb"]]]
let json = JSON(jsonObject)
// Generate the string representation of the JSON value
let jsonString = json.rawString(encoding: NSUTF8StringEncoding, options: nil)!
let params = ["filters" : jsonString, "limit": "1", "KEY": "my_key"]
Alamofire.request(.GET, "http://httpbin.org/post", parameters: params)
.responseString(encoding: NSUTF8StringEncoding) { request, response, content, error in
NSLog("Request: %# - %#\n%#", request.HTTPMethod!, request.URL!, request.HTTPBody.map { body in NSString(data: body, encoding: NSUTF8StringEncoding) ?? "" } ?? "")
if let response = response {
NSLog("Response: %#\n%#", response, content ?? "")
}
}
SWIFT 2
let string = "duke"
let jsonObject = ["$and":[["name":["$bw":string], "country":"gb"]]]
let json = JSON(jsonObject)
// Generate the string representation of the JSON value
let jsonString = json.rawString(NSUTF8StringEncoding)!
let params = ["filters" : jsonString, "limit": "1", "KEY": "my_key"]
Alamofire.request(.GET, "http://httpbin.org/post", parameters: params)
.responseString(encoding: NSUTF8StringEncoding) { request, response, result in
NSLog("Request: %# - %#\n%#", request!.HTTPMethod!, request!.URL!, request!.HTTPBody.map { body in NSString(data: body, encoding: NSUTF8StringEncoding) ?? "" } ?? "")
switch result {
case .Success(let value):
NSLog("Response with content: %#", value)
case .Failure(let data, _):
NSLog("Response with error: %#", data ?? NSData())
}
}
SWIFT 3 and Alamofire 4.0
let string = "duke"
let jsonObject = ["$and":[["name":["$bw":string], "country":"gb"]]]
let json = JSON(jsonObject)
// Generate the string representation of the JSON value
let jsonString = json.rawString(.utf8)!
let params = ["filters" : jsonString, "limit": "1", "KEY": "my_key"]
Alamofire.request("http://httpbin.org/post", method: .get, parameters: params)
.responseString { response in
#if DEBUG
let request = response.request
NSLog("Request: \(request!.httpMethod!) - \(request!.url!.absoluteString)\n\(request!.httpBody.map { body in String(data: body, encoding: .utf8) ?? "" } ?? "")")
switch response.result {
case .success(let value):
print("Response with content \(value)")
case .failure(let error):
print("Response with error: \(error as NSError): \(response.data ?? Data())")
}
#endif
}
This generates a GET request with the following URL:
http://httpbin.org/post?KEY=my_key&filters=%7B%22%24and%22%3A%5B%7B%22name%22%3A%7B%22%24bw%22%3A%22duke%22%7D%2C%22country%22%3A%22gb%22%7D%5D%7D&limit=1
That URL-Decoded is:
http://httpbin.org/post?KEY=my_key&filters={"$and":[{"name":{"$bw":"duke"},"country":"gb"}]}&limit=1

Related

cache json data from api to use it in table view swift 5

How can I Cache JSON from API ?
i Fetch the JSON from the API & Parse the JSON data. These can be done with the help of Alamofire & ObjectMapper
and this my way to do this
this my request function
Alamofire.request(URL(string: baseurl + serviceName) !,
method: .post,
parameters: parameters,
encoding: createEncoding(serviceName: serviceName),
headers: createHeaders(serviceName: serviceName))
.responseJSON {
(response: DataResponse < Any > ) in
if let status = response.response ? .statusCode {
print("URL: \(baseurl + serviceName)")
print("request \(String(describing: NSString(data: (response.request?.httpBody)!, encoding: String.Encoding.utf8.rawValue)))")
let data = response.data
let responseStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue) !as String
print("response \(responseStr)")
// String(data: response.request?.httpBody!, encoding: String.Encoding.utf8) as String!
switch (status) {
case 200:
do {
if let jsonArray =
try JSONSerialization.jsonObject(with: data!, options: []) as ? [
[String: AnyObject]
] {
let genericArray = Mapper < RS > ().mapArray(JSONArray: jsonArray)
let arr = [RS](JSONArray: jsonArray)
let base = RS()
base!.genericArray = arr
print(genericArray)
callBack_Handler(base!)
} else if
let genericResponse = RS(JSONString: responseStr) {
callBack_Handler(genericResponse)
}
} catch {
print("Error deserializing JSON: \(error)")
}
and this mapping model function
import ObjectMapper
Alamofire.request(URL(string: baseurl + serviceName) !,
method: .post,
parameters: parameters,
encoding: createEncoding(serviceName: serviceName),
headers: createHeaders(serviceName: serviceName))
.responseJSON {
(response: DataResponse < Any > ) in
if let status = response.response ? .statusCode {
print("URL: \(baseurl + serviceName)")
print("request \(String(describing: NSString(data: (response.request?.httpBody)!, encoding: String.Encoding.utf8.rawValue)))")
let data = response.data
let responseStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue) !as String
print("response \(responseStr)")
// String(data: response.request?.httpBody!, encoding: String.Encoding.utf8) as String!
switch (status) {
case 200:
do {
if let jsonArray =
try JSONSerialization.jsonObject(with: data!, options: []) as ? [
[String: AnyObject]
] {
let genericArray = Mapper < RS > ().mapArray(JSONArray: jsonArray)
let arr = [RS](JSONArray: jsonArray)
let base = RS()
base!.genericArray = arr
print(genericArray)
callBack_Handler(base!)
} else if
let genericResponse = RS(JSONString: responseStr) {
callBack_Handler(genericResponse)
}
} catch {
print("Error deserializing JSON: \(error)")
}
I will populate the parsed data in the Table View. It works when the user is in Online. How can I cache the data to show it when the user is offline?

Alamofire post request with body

I am trying to send POST HTTP request with body using Alamofire and would appreciate any help.
My body:
{"data":{"gym":{"country":"USA","city":"San Diego","id":1}}}
Should I do something like this?
let parameters: [String: Any] = [ "data": [
"gym": [
"country":"USA",
"city":"San Diego",
"id":1
]]]
Alamofire.request(URL, method: .post, parameters: parameters, headers: headers())
.responseJSON { response in
print(response)
}
If you wish to send the parameters in json format use encoding as JSONEncoding. So add parameter for encoding in request as follows:
Alamofire.request(URL, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers())
.responseJSON { response in
print(response)
}
Hope it helps...
Try this method to convert your json string to dictionary
func convertToDictionary(text: String) -> [String: Any]? {
if let data = text.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
let str = "{\"data\":{\"gym\":{\"country\":\"USA\",\"city\":\"San Diego\",\"id\":1}}}"
let dict = convertToDictionary(text: str)
and send dictionary as a param in your request.
Alamofire.request(URL, method: .post, parameters: dict, headers: headers())
.responseJSON { response in
print(response)
}
ref : How to convert a JSON string to a dictionary?
What I think is that you should try and prepare your dictionary in the this format:
var gym = [String:Any]()
gym["country"] = "USA"
gym["city"] = "San"
var data = [[String:Any]]()
data.append(gym)
var metaData = [String:Any]()
metaData["data"] = data
Your parameters is wrong...
let parameters: [String: Any] = { "data":
{
"gym": {
"country":"USA",
"city":"San Diego",
"id":1
}
}
}
Alamofire.request(<YOUR-URL>,
method: .post,
parameters: parameters,
encoding: URLEncoding(destination: .queryString),
headers: <YOUR-HEADER>
).validate().responseString { response in
switch response.result {
case .success:
debugPrint("Good to go.")
debugPrint(response)
case .failure:
let errMsg = String(data: response.data!, encoding: String.Encoding.utf8)!
debugPrint(errMsg)
debugPrint(response)
}
}
Hope this help. BTW, in Alamofire 5, debugPrint(response) can print out response.data directly.
You can use the httpBody property of URLRequest along with Alamofire Session request:
var req = try? URLRequest(url: url, method: method, headers: headers)
req?.httpBody = someJson
Alamofire.Session(configuration: .default).request(req!).validate().response { response in
// Handle the response
}

Access JSON value from Alamofire response

I am making a request to a local server that returns the following JSON:
{"session_key":"somecodexyz1234"}
The following code is is used to attempt to print the session_key value. But this is always evaluated tonil`.
Alamofire.request(url, method: .post, parameters: parameters).responseJSON(completionHandler: {
response in
print("Request: \(String(describing: response.request))")
print("Response: \(String(describing: response.response))")
print("Response code: \(String(describing: response.response?.statusCode))")
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)") // original server data as UTF8 string
}}
if response.data != nil {
let json = JSON(data: response.data!)
// changes
if let arr : NSArray = json as? NSArray
{
let sk = arr.value(forKey: "session_key") as? String
if sk != nil {print(sk)}
}
}
The following is output (the print(sk) is not executed as it is nil):
Request: Optional(http://127.0.0.1:5000/code)
Response: Optional(<NSHTTPURLResponse: 0x60800023f260> { URL: http://127.0.0.1:5000/code } { status code: 200, headers {
"Content-Length" = 40;
"Content-Type" = "application/json";
Date = "Sat, 23 Sep 2017 06:02:25 GMT";
Server = "Werkzeug/0.12.2 Python/3.4.3";
} })
Response code: Optional(200)
Data: "{\"session_key\":\"somecodexyz1234\"}"
Use below code to get response from almofire in json. In Your code, your are directly checking response.data instead of first check response.result as below.
Alamofire.request(requestURL, method:.post, parameters: param as? Parameters, encoding: URLEncoding(destination: .httpBody), headers: headers).responseJSON(completionHandler: { (response) in
switch response.result
{
case .success(let responseJSON):
// If request success then you will get response in json here
if responseJSON is String{
print("Reponse is string")
}
else if responseJSON is NSDictionary{
print("Reponse is Dictionary")
}
else if responseJSON is NSArray{
print("Reponse is Array")
}
else{
print("Any object")
return
}
print("Response : \((dicResponse)")
break
case .failure(let error):
// If request is failure then got error here.
break
}
})
You are using SwiftyJSON so why you again convert let arr : NSArray = json as? NSArray like this. You can simply do like this.
Alamofire.request(url, method: .post, parameters: parameters).responseJSON(completionHandler: {
response in
print("Request: \(String(describing: response.request))")
print("Response: \(String(describing: response.response))")
print("Response code: \(String(describing: response.response?.statusCode))")
if response.result.isSuccess, let result = response.result.value {
let json = JSON(result)
// Here is your session key
let sk = json["session_key"].stringValue
} else {
//Failure
}
})

Alamofire request with Parameters

I have this url : https://eee.com/geo?lat=10.2&lng=10.2
And i want to pass 2 parameters instead of 10.2. How should Alamofire request looks ?
if Request method is Get,May be
Alamofire.request("https://eee.com/geo?lat=10.2&lng=10.2").responseData { (dataResponse) in
if let data = dataResponse.data {
print(String(data: data, encoding: .utf8) ?? "")
}
}
if Request method is Post,May be
Alamofire.request("https://eee.com/geo", method: .post, parameters: [ "lat" :10.2,"lng":10.2 ] ).responseData { (dataResponse) in
if let data = dataResponse.data {
print(String(data: data, encoding: .utf8) ?? "")
}
}

Alamofire 4 and special characters in JSON

I've got a problem with special characters with Alamofire 4.The JSON contains æ, ø and å and the browser shows them fine, also my previous solution using SwiftyJSON did.Alamofire 4 shows something like this instead:
U00e6
Using this call:
Alamofire.request(specificURL, method: .get, parameters: param, encoding: URLEncoding.default, headers: nil).responseJSON { (response: DataResponse<Any>) in
print(response)
}
What to do to solve this?
Edit:
Alamofire.request(url, method: .get, parameters: param, encoding: JSONEncoding.default)
.responseJSON { response in
switch response.result {
case .success(let value) :
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value as! [String:AnyObject]!{
print("JSON: ",JSON)
self.arrUser = Mapper<Users>().mapArray(JSONArray:JSON["user"] as! [[String : Any]])!
self.tableView.reloadData()
}
case .failure(let encodingError):
//Print error
}
}
I got the issue that I have added æ in json response and try to print.
Output:
JSON: Optional(<__NSArrayI 0x600000050320>(
{
"email_address" = "testwts06#gmail.com";
username = "testwts06 \U00e6";
},
{
"email_address" = "testwts01#gmail.com";
username = "testwts01 \U00eb";
},
{
"email_address" = "testwts100#gmail.com";
username = testwts100;
})
While displaying it display in correct format.
Swift 3 update for Ekta's answer:
let encodedURL = specificURL.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
Seems the typical serialization error due to wrong JSON encoding, probably your response status code is 3840.
JSON text SHALL be encoded in UTF-8, UTF-16, or UTF-32.
You could try to convert the response data to correct UTF8 encoding:
let datastring = NSString(data: response.data!, encoding: String.Encoding.isoLatin1.rawValue)
let data = datastring!.data(using: String.Encoding.utf8.rawValue)
do {
let object = try JSONSerialization.jsonObject(with: data!, options: .allowFragments)
let jsonDic = object as! NSDictionary
print(" ok, successfully converted..\(jsonDic)")
} catch let aError as Error {
// print and handle aError
}
Hope it helps you.
Here is a simple String extension that solves the issue:
extension String {
func fixUnicode() -> String {
var copy = self as NSString
let regex = try! NSRegularExpression(pattern: "\\\\U([A-Z0-9]{4})", options: .caseInsensitive)
let matches = regex.matches(in: self, options: [], range: NSMakeRange(0, characters.count)).reversed()
matches.forEach {
let char = copy.substring(with: $0.rangeAt(1))
copy = copy.replacingCharacters(in: $0.range, with: String(UnicodeScalar(Int(char, radix: 16)!)!)) as NSString
}
return copy as String
}
}

Resources