Getting JSON array with Alamofire + SwiftyJSON - swift

I'm really new to Swift, sorry if this is a dumb question... there seem to be many questions about this but none of them use the latest version of Alamofire
Alamofire.request(.GET, url)
.responseJSON { response in
let json = JSON(response.data!)
debugPrint(json)
self.delegate?.didReceiveAPIResults(json)
}
And the delegate's didReceiveAPIResults method
func didReceiveAPIResults(results: JSON) {
dispatch_async(dispatch_get_main_queue(), {
self.tableData = results["items"].arrayObject!
self.appsTableView!.reloadData()
})
}
Here's the JSON response:
{
"items": [
{
"id": 1,
"name": "Sample 1"
},
{
"id": 2,
"name": "Sample 2"
}
]
}
I expect the debugPrint to print something similar to that JSON, but instead it just prints unknown
If I debugPrint response.data by itself, it appears to be encoded...
Optional(<7b226461 7461223a 5b7b2269 64223a36 2c226e61 6d6522......
Then my results["items"].arrayObject! line has this error:
fatal error: unexpectedly found nil while unwrapping an Optional value

Rather than grabbing response.data, I'd suggest grabbing response.result.value. When you do responseJSON, Alamofire does the JSON parsing for you, and you should feel free to just grab this parsed object.
Alamofire.request(.GET, url)
.responseJSON { response in
if let value = response.result.value {
let json = JSON(value)
self.delegate?.didReceiveAPIResults(json)
}
}

Related

Alamofire not getting full response

I'm trying to fetch data from a GET request using Alamofire in Swift. There's an issue where it's not getting the full response from the request. The response is an array with nested arrays some String and some [String:Any]. I've none of the [String:Any] gets pulled in using Alamofire and think this is a serious bug. Postman shows the nested array values but not Alamofire.
The request
Alamofire.request(request.getFullUrl(param: paramsForUrl), method: request.getMethodType(), parameters: data, encoding: request.getEncoding(), headers: headers).validate(statusCode: 200..<500).responseJSON { response in }
What a typical response should look like
{
"uuid": "787FDS8-FS7FS7DG9-FSD789FCS98",
"name": "Show time",
"views_count": 0,
"comments_count": 0,
...
"events": [
{
"uuid": "f69a358e-9a1e-427c-a158-95dfc8c54ed7",
"name": "Test",
...
},
{
"uuid": "8993b639-f6c9-4d20-b8a9-c43c73a9828b",
"name": "Test 2",
...
},
...
]
"times: [
{
"name: "test time 1",
"clock: "Face"
},
{
"name": "test time 2",
"clock: "Back"
}
]
}
What's missing
Anything inside nested arrays: events, times. If I have a simple array of String then Alamofire gets these. It doesn't show anything nested and this is with both printing response.result.value and JSON decoding the response and accessing events directly. It doesn't see events or times.
Thanks for your help.
May be your JSON is not valid. To check that try changing responseJSON to responseString and see if it prints all the data e.g.
Alamofire.request(url ,method: .get ,parameters: data).validate().responseString{ response in
switch response.result{
case .success:
let s = response.result.value ?? "nil"
print("API Response: \(s)")
case .failure:
debugPrint(response)
}
}
If the above is printing all the data from your server than you need to fix the service
Delete .validate(statusCode: 200..<500) and try again.
Alamofire.request(url ,method: .get ,parameters: parameter).responseJSON{ response in
switch response.result{
case .success:
let value = response.result.value ?? "nil"
print("API Response: \(value)")
case .failure:
print("error")
}
}

Correct way to retrieve json data from remote url using swift 4 for an array

I am trying to see what is the latest and greatest way to retrieve json data in swift 4 (using Codable structure).
I have the following json data in a remote url:
[
{
"products": [
{
"productid": "01",
"price": "01"
},
{
"productid": "02",
"price": "02"
}
]
}
]
I have also setup the corresponding codable structure. My questions is what would be the correct way to retrieve this data using the latest techniques for swift 4.
I am seeing various ways such as:
DataManager.getJSONFromURL ...
let jsonData = try Data(contentsOf: URL ...
let task = URLSession.shared.dataTask(with: url) ...
try JSONSerialization.data...
I would like to know which is the correct (latest) format for retrieving json data using swift 4 from a remote URL. Thank you.
I found the answer to my question.
Apple announced Swift 4 as part of Xcode 9 at WWDC 2017. It brings some really nice improvements to existing Swift 3 features as well as stability. The latest ways of working with REST API in Swift 4 is using URLSession and JSONDecoder. The later was introduced with Swift 4.
In Swift 3, most of developers used third party frameworks such as SwiftyJson and Alamofire in order to work with REST APIs. The reason for this, most of the time, was that parsing JSON using Swift was very tedious. More precisely - you had to set up initializer in your Model, had to do loops to assign values in your controller, had to typecast values and so on. You could always copy/paste your code, but still it was overwhelming. With Swift 4 all you will need to do is to write just a single line to decode and parse JSON.
URLSession and JSONDecoder are all you need in Swift 4 for retrieving json data from a remote url.
For more information and an example, you can check this site:
URLSession and JSONDecoder in Swift 4
func getRequestWithUrl(url : String ,onCompletionHandler : #escaping ([String : Any]?) -> Void){
let headers : HTTPHeaders = [
"X-Api-Key": "EPE67704498C76B16CF29B956B2A2E91",
"Accept": "application/json",
]
Alamofire.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers).responseJSON { (response) in
switch response.result {
case .success:
onCompletionHandler(response.result.value as? [String : Any])
break
case .failure(_):
onCompletionHandler(nil)
}
}
}
we have an API which allows us to create a new board with a title “New
York Highlights”. For this, using Alamofire the code is very easy:
AF.request("https://api.mywebserver.com/v1/board", method: .get, parameters: ["title": "New York Highlights"])
.validate(statusCode: 200..<300)
.responseDecodable { (response: DataResponse) in
switch response.result {
case .success(let board):
print("Created board title is \(board.title)") // New York Highlights
case .failure(let error):
print("Board creation failed with error: \(error.localizedDescription)")
}
}
For Alamofire you need to install framework for more detail read this document
Doing exactly the same with the URLSession API requires a bit more of
work.
enum Error: Swift.Error {
case requestFailed
}
// Build up the URL
var components = URLComponents(string: "https://api.mywebserver.com/v1/board")!
components.queryItems = ["title": "New York Highlights"].map { (key, value) in
URLQueryItem(name: key, value: value)
}
// Generate and execute the request
let request = try! URLRequest(url: components.url!, method: .get)
URLSession.shared.dataTask(with: request) { (data, response, error) in
do {
guard let data = data,
let response = response as? HTTPURLResponse, (200 ..< 300) ~= response.statusCode,
error == nil else {
// Data was nil, validation failed or an error occurred.
throw error ?? Error.requestFailed
}
let board = try JSONDecoder().decode(Board.self, from: data)
print("Created board title is \(board.title)") // New York Highlights
} catch {
print("Board creation failed with error: \(error.localizedDescription)")
}
}
credit

Alamofire responseArray String array for keyPath

I have a rest call which returns array of string [String] for keyPath "data", for example...
{
"data": [
"1",
"3",
"5",
"2",
"4",
"9"
]
}
I am trying to get it via responseArray(keyPath: "data"), but get compile error for line *.responseArray(keyPath: "data") {(response: DataResponse<[String]>) in*
Cannot convert value of type '(DataResponse<[String]>) -> ()' to expected argument type '(DataResponse<[_]>) -> Void'
Part of request example
alamofireManager.request(url)
.responseArray(keyPath: "data") {(response: DataResponse<[String]>) in
if response.result.isSuccess {
if let data = response.result.value {
//process success
} else {
// handle error
}
}
...
Does anybody of you know how to do it ?
The problem is that String isn't Mappable. As per https://github.com/Hearst-DD/ObjectMapper/issues/487, these are the proposed solutions:
In this situation I would recommend accessing the data directly from the Alamofire response. You should be able to simply cast it to [String].
Alternatively, you may be able to subclass String and make the subclass Mappable, however I think that is more work than necessary for the your situation
Using Swift's 4 Codable (no external dependencies):
struct APIResponse: Decodable {
let data: [String]
}
let url = "https://api.myjson.com/bins/1cm14l"
Alamofire.request(url).responseData { (response) in
if response.result.isSuccess {
if let jsonData = response.result.value,
let values = try? JSONDecoder().decode(APIResponse.self, from: jsonData).data {
//process success
print(values)
} else {
// handle error
}
}
}

if else conditions executed at the same time in swift

I'm parsing this json from a REST API with SwiftyJSON:
{
"status": {
"code": 201,
"description": "success"
},
"result": [
{
"id": "5951e8eee0207e049c339691",
......
}
]
}
After sending the request with Alamofire and getting the response is when I run into an issue:
case .success:
if let value = response.result.value {
let json = JSON(value)
print(json)
if json["status"]["code"].intValue == 201 {
self.jsonData = json["result"].arrayValue
self.mytableView.reloadData()
print("realoded tableView")
}else{
HUD.show(.error)
HUD.hide(afterDelay: 0.5)
HUD.flash(.label("message"), delay: 3.0){ _ in
print("fail message")
}
}
}
myTableView reloads the data, and the console shows the print message. However, the HUD is also showing a message, and the console logs the fail message.
P.S. I have also tried to compare as a string with json["result"]["code"].stringValue == "201". This does the same tableview update, but the hud is shown the hud is managed with PKHUD library.

Alamofire always enter on Failure status

I am trying to make a request with Alamofire and Swift 3.0 but it is always going to the failure status.
This is the code I have right now:
let str = "http://url/{\"user\":\"1\",\"pass\":\"1\"}"
let encodedUrl = str.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
Alamofire.request(encodedUrl!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in
switch(response.result) {
case .success(_):
print("Success")
break
case .failure(_):
print("Failure")
break
}
}
If I use the encodedUrl on Postman application I get the response well. It gives to me the following JSON:
[
{
"user": "1",
"name": "peter"
},
{
"user": "4",
"name": "andrew"
}]
What am I missing?
Thanks in advance!
Finally, it seems that I was retrieving an extra String out of the JSON because I used an echo on my API.
I could not see it because I had on Postman the option to show the response as JSON so the String was not being shown. I have changed it to HTML and then I was able to see the String.
Removing the extra String let me enter on the success status of Alamofire.