how to get the response JSON in swift - ios

I got a response from my Alamofire post request. I want to get the Status code from the response.
Here in the code:
case .success(let upload, _, _):
upload.responseJSON { response in
print(response.result.value!)
}
Here is the response looks like:

The value property of the response's result is a dictionary. You can extract status like this:
let json = response.result.value as? [String: Any]
if let status = json?["status"] as? Int {
print(status)
}

Use responseDecodable in Alamofire 5 with Codable Structure
Replace responseJSON with responseDecodable.
.responseDecodable { (response: AFDataResponse<ProfileModel>) in
switch response.result {
case .success(let profileModel):
switch profileModel.status {
case 200:
print("success")
case 101:
print("sessionExpire")
default:
print("default")
}
case .failure(let error):
print("failure")
}
}
ProfileModel
struct ProfileModel: Codable {
let status: Int
let type: String
let data: ProfileDataModel
}
struct ProfileDataModel: Codable {
let ImagePath: String
let ThumbImagePath: String
}

Related

How to convert '__NSIArrayI' to JSON Array in Swift?

I am new to Swift 4 and working on an iOS app. I have the following JSON data retrieved from the server which will be extracted to data table.
[
{
"fund_nav_validity":"24 August to 31 August 2016\n",
"fund_nav_cost":10,
"fund_nav_sell":9.85,
"nav_id":118,
"fund_nav_buy":10,
"fund_id":1,
"nav_as_on_date":"24-Aug-16",
"fund_nav_market":9.95
},
{
"fund_nav_validity":"04 September to 07 September 2016\n",
"fund_nav_cost":10,
"fund_nav_sell":9.85,
"nav_id":117,
"fund_nav_buy":10,
"fund_id":1,
"nav_as_on_date":"01-Sep-16",
"fund_nav_market":9.95
}
]
I have done following task in the navdata function to retrieve the '__NSIArrayI' to JSON:
func getNAVData(){
Alamofire.request(url, method: .post).responseJSON{
response in
if response.result.isSuccess{
print("Success")
//let navDataJSON : JSON = JSON(response.result.value!
let navDataJSON : JSON = JSON(response.result.value!)
print(navDataJSON)
}else{
print("Failed")
}
}
}
I need to convert it to JSON Array which is done in java. How to do the similar task in Swift 4?
you are in the right way, in here you need to convert your JSON response to array the reason your json started with this type[{}] and check your JSON response contains the value or not in intially. try the below code
if response.result.isSuccess{
print("Success")
// convert your JSON to swiftyJSON array type if your JSON response as array as well as check its contains data or not
guard let resJson = JSON(responseObject.result.value!).array , !resJson.isEmpty else { return
}
// create the Swifty JSON array for global access like wise
var navDataJSON = [JSON]() //[JSON]() --> Swifty-JSON array memory allocation.
navDataJSON = resJson
}
You're getting the JSON array and if you want to convert to model Array then you can use create Model Struct and confirm to Decodable Protocol, without using SwiftyJSON using inbuilt solution to parse JSON.
import Foundation
// MARK: - Element
struct Model: Decodable {
let fundNavValidity: String
let fundNavCost: Int
let fundNavSell: Double
let navId: Int
let fundNavBuy: Int
let fundId: Int
let navAsOnDate: String
let fundNavMarket: Double
enum CodingKeys: String, CodingKey {
case fundNavValidity = "fund_nav_validity"
case fundNavCost = "fund_nav_cost"
case fundNavSell = "fund_nav_sell"
case navId = "nav_id"
case fundNavBuy = "fund_nav_buy"
case fundId = "fund_id"
case navAsOnDate = "nav_as_on_date"
case fundNavMarket = "fund_nav_market"
}
}
then in getNAVData method you can use JSONDecoder to covert to Model struct array like below
func getNAVData() {
Alamofire.request(url, method: .post).responseJSON {
response in
switch response.result {
case .success(let data):
do {
let modelArray = try JSONDecoder().decode([Model].self, from: data)
print(modelArray)
} catch {
print("Error: \(error)")
}
case .failure(let error):
print(error.localizedDescription)
}
}
}
If you want to use SwiftyJSON return responseData rather than responseJSON. This avoids a double conversion, and handle always a potential error
func getNAVData(){
Alamofire.request(url, method: .post).responseData { response in
switch response.result {
case .success(let data):
let navDataJSON = JSON(data).arrayValue
print(navDataJSON)
case .failure(let error): print(error)
}
}
}
The result navDataJSON is a JSON array.
However in Swift 4+ it's highly recommended to use the more efficient and built-in Codable protocol
struct Fund : Decodable {
let fundNavValidity, navAsOnDate : String
let fundNavCost, navId, fundNavBuy, fundId : Int
let fundNavSell, fundNavMarket : Double
}
func getNAVData(){
Alamofire.request(url, method: .post).responseData { response in
switch response.result {
case .success(let data):
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let navDataJSON = decoder.decode([Fund].self, from : data)
print(navDataJSON)
} catch { print(error) }
case .failure(let error): print(error)
}
}
}
The result is an array of Fund structs.

errors decoding json with Alamofire

I try to decode JSON data from web using Alamofire. My app is sending the same GET requests, which differs by id. Some JSON is decoded successfully, but some can not be decoded. What can be the problem? How can I solve this issue? All responses are checked by JSON validator and are valid. Trying to decode with URLSession.shared.dataTask(with: url) just cannot decode a single response, even response that was successfully decoded with Alamofire
Code is:
var hostURL = "https://public-api.nazk.gov.ua/v1/declaration/"
hostURL = hostURL + declarationID
print(hostURL)
Alamofire.request(hostURL).responseData { response in
switch response.result {
case .success(let data):
let declarationInfoElement = try? JSONDecoder().decode(DeclarationInfoElement.self, from: data)
print(declarationInfoElement)
case .failure:
print("fail")
}
}
Console output is:
https://public-api.nazk.gov.ua/v1/declaration/3509369f-b751-444a-be38-dfa66bb8728f
https://public-api.nazk.gov.ua/v1/declaration/3e7ad106-2053-48e4-a5d2-a65a9af313be
https://public-api.nazk.gov.ua/v1/declaration/743b61d5-5082-409f-baa0-9742b4cc2751
https://public-api.nazk.gov.ua/v1/declaration/5d98b3d9-8ca6-4d5d-b39f-e4de98d451aa
https://public-api.nazk.gov.ua/v1/declaration/7e3c488c-4d6a-49a3-aefb-c760f317dca4
nil
Optional(Customs_UA.DeclarationInfoElement(id: "4647cd5d-5877-4606-8e61-5ac5869b71e0")
nil
nil
nil
#objc func getJSON(){
let hostURL = "https://public-api.nazk.gov.ua/v1/declaration/"
print(hostURL)
Alamofire.request(hostURL).responseData { response in
switch response.result {
case .success(let data):
do {
if let json = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? Dictionary<String,Any>
{
print(json)
} else {
print("bad json")
}
} catch let error as NSError {
print(error)
}
print(data)
case .failure:
print("fail")
}
}
}
The problem is that some parameters of the JSON are optional. You have to post your DeclarationInfoElement class to check.
Use something like this to detect the error.
class DeclarationInfoElement: Decodable {
let id: String?
let created_date: String?
/// and so on
}

Parsing JSON Lines with Alamofire/Codable

Is it possible to parse JSON lines with Alamofire and codable?
Here is my code right now.
Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers).responseString {(response) in
switch response.result {
case .success(let value):
print ("response is \(value)")
case .failure(let error):
print ("error is \(error)")
}
}
This prints all the JSON lines as a string but I want to serialize the response as an array of JSON. How would I do that? The problem with JSON lines is that it returns each set of json on a separate line so it is not familiar to alamofire.
Here is what I tried as if this was traditional JSON which obviously it is not so this did not work:
Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers).responseJSON {(response) in
switch response.result {
case .success(let value):
print ("response is \(value)")
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
let data = try! JSONSerialization.data(withJSONObject: value)
do {
let logs = try decoder.decode([Logs].self, from: data)
completion(logs)
} catch let error {
print ("error parsing get logs: \(error)")
}
case .failure(let error):
print ("failed get logs: \(error) ** \(response.result.value ?? "")")
}
}
For anybody unfamiliar with json lines here is the official format info: http://jsonlines.org
{"_logtype":"syslogline","_ingester":"agent","_ip":"40.121.203.183","pid":5573,"program":"docker","_host":"k8s-master-5A226838-0","logsource":"k8s-master-5A226838-0","_app":"syslog","_file":"/var/log/syslog","_line":"docker[5573]: I0411 00:18:39.644199 6124 conversion.go:134] failed to handle multiple devices for container. Skipping Filesystem stats","_ts":1491869920198,"timestamp":"2017-04-11T00:18:39.000Z","_id":"804760774821019649"}
{"_logtype":"syslogline","_ingester":"agent","_ip":"40.121.203.183","pid":5573,"program":"docker","_host":"k8s-master-5A226838-0","logsource":"k8s-master-5A226838-0","_app":"syslog","_file":"/var/log/syslog","_line":"docker[5573]: I0411 00:18:39.644167 6124 conversion.go:134] failed to handle multiple devices for container. Skipping Filesystem stats","_ts":1491869920198,"timestamp":"2017-04-11T00:18:39.000Z","_id":"804760774821019648"}
{"_logtype":"syslogline","_ingester":"agent","_ip":"40.121.203.183","pid":5573,"program":"docker","_host":"k8s-master-5A226838-0","logsource":"k8s-master-5A226838-0","_app":"syslog","_file":"/var/log/syslog","_line":"docker[5573]: I0411 00:18:37.053730 6124 operation_executor.go:917] MountVolume.SetUp succeeded for volume \"kubernetes.io/secret/6f322c04-e1d2-11e6-bca0-000d3a111245-default-token-swb07\" (spec.Name: \"default-token-swb07\") pod \"6f322c04-e1d2-11e6-bca0-000d3a111245\" (UID: \"6f322c04-e1d2-11e6-bca0-000d3a111245\").","_ts":1491869917193,"timestamp":"2017-04-11T00:18:37.000Z","_id":"804760762212941824"}
Here is an example of writing custom DataSerializer in Alamofire that you could use for decoding your Decodable object.
I am using an example from random posts json url https://jsonplaceholder.typicode.com/posts
Here is an example of Post class and custom serializer class PostDataSerializer.
struct Post: Decodable {
let userId: Int
let id: Int
let title: String
let body: String
}
struct PostDataSerializer: DataResponseSerializerProtocol {
enum PostDataSerializerError: Error {
case InvalidData
}
var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<[Post]> {
return { request, response, data, error in
if let error = error {
return .failure(error)
}
guard let data = data else {
return .failure(PostDataSerializerError.InvalidData)
}
do {
let jsonDecoder = JSONDecoder()
let posts = try jsonDecoder.decode([Post].self, from: data)
return .success(posts)
} catch {
return .failure(error)
}
}
}
}
You could simply hook this upto your Alamofire client which sends request to remote url like so,
let request = Alamofire.request("https://jsonplaceholder.typicode.com/posts")
let postDataSerializer = PostDataSerializer()
request.response(responseSerializer: postDataSerializer) { response in
print(response)
}
You could also do additional error checking for the error and http response code in serializeResponse getter of the custom serializer.
For you json line, it seems that each json object is separated with new line character in so called json line format. You could simply split the line with new line characters and decode each line to Log.
Here is Log class I created.
struct Log: Decodable {
let logType: String
let ingester: String
let ip: String
let pid: Int
let host: String
let logsource: String
let app: String
let file: String
let line: String
let ts: Float64
let timestamp: String
let id: String
enum CodingKeys: String, CodingKey {
case logType = "_logtype"
case ingester = "_ingester"
case ip = "_ip"
case pid
case host = "_host"
case logsource
case app = "_app"
case file = "_file"
case line = "_line"
case ts = "_ts"
case timestamp
case id = "_id"
}
}
And custom log serializer that you could use with your Alamofire. I have not handled error in the following serializer, I hope you can do it.
struct LogDataSerializer: DataResponseSerializerProtocol {
enum LogDataSerializerError: Error {
case InvalidData
}
var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<[Post]> {
return { request, response, data, error in
if let error = error {
return .failure(error)
}
guard let data = data else {
return .failure(LogDataSerializerError.InvalidData)
}
do {
let jsonDecoder = JSONDecoder()
let string = String(data: data, encoding: .utf8)!
let allLogs = string.components(separatedBy: .newlines)
.filter { $0 != "" }
.map { jsonLine -> Log? in
guard let data = jsonLine.data(using: .utf8) else {
return nil
}
return try? jsonDecoder.decode(Log.self, from: data)
}.flatMap { $0 }
return .success(allLogs)
} catch {
return .failure(error)
}
}
}
}
Alamofire is extensible, so I'd suggest writing your own response ResponseSerializer that can parse JSON by line. It seems that each line should parse fine, they're just not parseable together since the whole document isn't valid JSON.

Alamofire receive and parse an array of strings swift

I getting the result as an array of strings like this
["India","America","Australia","China","Russia"]
And I'm using Alamofire to get the response using code. There's no error, but I got the result as null. Please help in parsing this.
sessionManager?.request(strURL, method: method, parameters: params, encoding: encoding , headers: headers).responseJSON { (response) in
switch response.result {
case .success:
let resJson = JSON(response.result.value!)
success(resJson)
break
case .failure(let error):
failure(error as NSError)
break
}
}
Try this:
if let responseData = response.result.value{
let responsevalue = responseData as? [String]
}
For anyone looking for another derived answer, just put this chunk of code after Alamofire.request(...):
.responseJSON(completionHandler: { (response) in
switch response.result{
case .success(let value):
// Here is your array of String
let arrayOfStrings = value as? [String]
case .failure(let error):
// Some code when error happens...
print(error.localizedDescription)
}
})
This solution using SwiftyJSON:
.responseJSON(completionHandler: { (response) in
switch response.result{
case .failure(let error):
print(error.localizedDescription)
case .success(let res):
let json = JSON(res)
let res = json["result"]
var models = [String]()
if let models1 = company["models"].array {
for model in models1 {
guard let mod = model.string else { return }
models.append(mod)
}
}
}
})

Error Handling with Alamofire in Swift 2

Hi I am practising some code, my code is fine with case .Success(let value): and it is displaying alert but will case .Failure(let error): display alert with The 4xx class of status code?
Alamofire.request(.GET, URL).responseJSON { (response) -> Void in
if let value = response.result.value {
let json = JSON(value)
switch response.result {
case .Success(let value):
let name = json["name"].string
if let nothing = name {
self.alertMessage(message: "Name not Found")
} else {
self.alertMessage(message: "Name Found")
}
case .Failure(let error):
self.alertMessage(message: "Error 4xx / 5xx")
}
You can use validate to check status codes:
Alamofire.request(.GET, URL)
.validate() // or, if you just want to check status codes, validate(statusCode: 200..<300)
.responseJSON { response in
switch response.result {
case .Success(let value):
let json = JSON(value)
if let name = json["name"].string {
self.alertMessage(message: "Name Found: \(name)")
} else {
self.alertMessage(message: "Name not Found")
}
case .Failure(let error):
self.alertMessage(message: "Error 4xx / 5xx: \(error)")
}
}
Or, in Swift 3:
Alamofire.request(url)
.validate() // or, if you just want to check status codes, validate(statusCode: 200..<300)
.responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
if let name = json["name"].string {
self.alertMessage(message: "Name Found: \(name)")
} else {
self.alertMessage(message: "Name not Found")
}
case .failure(let error):
self.alertMessage(message: "Error 4xx / 5xx: \(error)")
}
}
Also note that you should probably move the examination of response.result.value to inside the Success section (or just grab the value passed there). Also, the determination of whether name is found was backwards.

Resources