Alamofire 4 and special characters in JSON - ios

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
}
}

Related

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.

how tobuild url request with get method using alamofire

I am not aware of building api with dynamic values.I have an api and from that, i want to get pluscode by sending url request with latitude, longitude and email to base url.My requirement is sending request in get method with lat,long and email values and getting pluscode from response.Can anyone help me to build this url.
lat = locValue.latitude
long = locValue.longitude
email = abcdefg#gmail.com
//base url
var pluscodeurl = "https://plus.codes/api?address="
let postParameters = ["address":lat+long ,"email":"mahithaa.angadi#gmail.com"] as [String : Any]
Alamofire.request(pluscodeurl, method: .get, encoding: URLEncoding.default, headers: nil).responseJSON { response in
switch response.result {
case .success:
print(response)
case .failure(_):
break
}
}
Here is the snippet you can write it
let lat = "19.0760"
let long = "72.8777"
let email = "abc#test.com"
let ApiURL = "https://plus.codes/api?address=\(lat),\(long)&email=\(email)"
Alamofire.request(ApiURL).responseJSON { response in
print("Result: \(response.result)")
if let json = response.result.value {
print("JSON: \(json)")
}
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)")
}
}
You can write your url in the below format:
let email = "abc#gmail.com"
let pluscodeurl = "https://plus.codes/api?address=\(lat),\(long)&email=\(email)"

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
}

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)")
}
}
}

cannot parse json using swift in iOS

I'm trying to get value from json but it is giving this error
type of expression is ambiguous without more context
My ViewController code is
Alamofire.request(.GET, "http://resturl.com/rest/loginuser",
parameters: ["password":uPwd,"username": uEmail,], encoding: .JSON).responseJSON() {
(request,response, data,error) in
let jsonData = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &error) as? NSDictionary // it is giving error here
if let parseJson=jsonData{
var result:String=parseJson[""] as String!;
}
}
I've searched internet but couldn't find any appropriate solution. Please guide me with this
Alamofire.request(.GET, "http://resturl.com/rest/loginuser",
parameters: ["password":uPwd,"username": uEmail,], encoding: .JSON)
.responseJSON { _, _, JSON, _ in
if let parseJson=JSON{
println(parseJson)
}
}
First thing the data will return in json format. So don't need to convert it in json format. So please use my code. Hope it will help you.
Second thing remove last semicolon(, ) which is extra in this line.
["password":uPwd,"username": uEmail,]
Alamofire.request(.GET, "http://resturl.com/rest/loginuser",
parameters: ["password": uPwd,"username": uEmail], encoding: .JSON).responseJSON() {
(request,response, data,error) in
if let jsonData : NSDictionary = data as! [NSDictionary : AnyObject]{
// do stuff over here
}
else{
println(data)
println(error)
}
}

Resources