How does "let JSON" work in Alamofire/Swift - json

From here I see that the proper Alamofire 2/Swift 2 syntax when dealing with a JSON response is:
Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
.responseJSON { request, response, result in
switch result {
case .Success(let JSON):
print("Success with JSON: \(JSON)")
case .Failure(let data, let error):
print("Request failed with error: \(error)")
if let data = data {
print("Response data: \(NSString(data: data, encoding: NSUTF8StringEncoding)!)")
}
}
}
How and where is the let JSON defined? (From a Swift point of view.)
I see in a request extension that ResponseSerializer returns .Success(JSON) but why is the handler not defined like a usual function:
case .Success(JSON: AnyObject?) {
print("Success with JSON: \(JSON)")
}
or better yet:
case .Success(JSON: NSDictionary?) {
print("Success with NSDictionary: \(JSON)")
}

result is enum with cases .Success, .Failure. Enum cases in Swift can hold some value (by the way, that's how Optionals in Swift work, they are enums with two cases Some: which wraps a value and None). By calling case .Success(let JSON): in switch you assign this value to JSON constant and you can use it in case block. Type of this constant is automatically inferred.
For more information about it, check paragraph "Associated Values" in Swift Language Guide

Related

Parse JSON when I get a error response in Alamofire

I've been working on API requests using Alamofire, and I want to know something for parsing the Error and to get the JSON data from the server instead of accessing the AFErrors. The code below works fine, but since I've been using .responseDecodable for decoding the response and also the MyError inherits Decodable, I was wondering if there is a similar way to decode data when I get the error response back, instead of using JSONDecoder().decode.
When I get the error response, it returns a JSON object with one value in it (message) from the server.
static let sessionManager: Session = {
let configuration = URLSessionConfiguration.af.default
configuration.timeoutIntervalForRequest = 30
return Session(configuration: configuration)
}()
Request.sessionManager.request(endpoint, method: httpMethod, parameters: params, headers: headers)
.responseDecodable(of: resDecodeType.self) { response in
switch response.result {
case .success(let successResponse):
completed(.success(successResponse))
case .failure(let error):
let errorStatusCode = response.response?.statusCode
do {
let data = try JSONDecoder().decode(MyError.self, from: response.data!) // -> this part...
} catch {
print(error)
}
}
}
}
struct MyError: Decodable {
let message: String
}

Issue To Create A Base Service <Alamofire,PromiseKit,Generic>

Hello everyone I want to crate a base api service for my apps but when I try a lot of different way but i can't solve my problems. I have to use alamofire, promiseKit and generic's.
My first solution and his issue: I can get my json from api but when I try to decode my json every time it fails. There is the code:
func fetchData<T: Codable>(_ page: Int) -> Promise<T> {
let path = getPath(page)
return Promise<T> { seal in
AF.request(path, method: .get).validate(statusCode: 200..<300).responseString { response in
switch response.result {
case .success(let data):
if let json = data.data(using: .utf8) {
do {
let res = try JSONDecoder().decode(T.self, from: json)
print(res)
seal.fulfill(res)
} catch {
print("json serilaztion error")
print(error)
seal.reject(error)
}
}
case .failure(let error):
seal.reject(error)
}
}
}
}
My second solution and issue : When I do my request I get my json response and decode it but in this solution I can't return data with seal.fulfill(data) gives me "Cannot convert value of type 'Any' to expected argument type 'T'" and when I try to seal.fulfill(data as! T) like this when I run app always crashes. There is my code :
func fetchData<T: Codable>(_ page: Int) -> Promise<T> {
let path = getPath(page)
return Promise<T> { seal in
AF.request(path, method: .get).validate(statusCode: 200..<300).responseJSON { response in
switch response.result {
case .success(let data):
seal.fulfill(data as! T) // Cannot convert value of type 'Any' to expected argument type 'T'
case .failure(let error):
seal.reject(error)
}
}
}
}
Finally I'm using test api https://www.flickr.com/services/api/explore/flickr.photos.getRecent to test my code. How I can solved this issue's ? Thanks for your helps
Use responseDecodable instead of responseString or responseJSON.
AF.request(...).responseDecodable(of: T.self) { response in
...
}

JSON.dictionaryObject is null in Alamofire swift 3

I have a JSON in following format:
postJson ={"firstname":"Vishal","lastname":"raskar","username":"vishal123","password":"123456","confirmpassword":"123456","email":"raskarvishal7#gmail.com","timezone":"1","accountid":"12345","phoneno":"8655012753"}
(Data type of postJson is JSON i.e swiftyJSON)
Now I want to hit on server through Alamofire, so I need to Post JSON data in dictionary format in parameters : ___, e.g.:
Alamofire.request(URL, method: .post, parameters: postJson.dictionaryObject, encoding: JSONEncoding.default,headers: "Content-Type": "application/json").responseJSON { response in switch response.result {
case .success(let data):
case .failure(let error):
}
so basically I tried to convert my JSON in dictionary by postJson.dictionaryObject. But always gets null from postJson.dictionaryObject (even though data is present in postJson).
I tried all combinations like postJson.dictionaryValue, postJson.dictionary, but no success.
I then tried to convert postJson to Data, and then dictionary:
if let data = postJson.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: AnyObject]
}
catch {
print(error.localizedDescription)
}
}
and then post through Alamofire, now getting response. What am I doing wrong? I want to use my first option.
Assuming you are using Swift 3 / Alamofire 4.0
This is how you would define the "parameters" parameter according to Alamofire documentation:
let parameters: Parameters = ["foo": "bar"]
Alamofire.request(urlString, method: .get, parameters: parameters, encoding: JSONEncoding.default)
.downloadProgress(queue: DispatchQueue.global(qos: .utility)) { progress in
print("Progress: \(progress.fractionCompleted)")
}
.validate { request, response, data in
// Custom evaluation closure now includes data (allows you to parse data to dig out error messages if necessary)
return .success
}
.responseJSON { response in
debugPrint(response)
}
To learn more, click here

Can't pull value from json data

I've seen a number of questions and answers addressing this. I've tried it and I can't figure it out. I've accessed my owner server's responseJSON no problem. But now I am trying to consume a 3rd party API and am having trouble. I am using Alamofire and SwiftyJSON.
let json = JSON(data: data)
this is what json looks like:
{"maxResults":50,"startAt":0,"isLast":true,"values":[{"id":1,"self":"https://stackrank.atlassian.net/rest/agile/1.0/board/1","name":"JI board","type":"scrum"},{"id":2,"self":"https://stackrank.atlassian.net/rest/agile/1.0/board/2","name":"Board2","type":"scrum"}]}
Why can't i access any of the values?
json["maxResults"].numberValue gives me '0'
json["values"].arrayValue give me an empty array []
I've seen a bunch of answers regarding the encoding etc...but I couldn't get it to work.
Here is the snippet from Alamofire showing the response format:
Alamofire.request(request).responseJSON {
response in
switch response.result {
case .success:
success(response.data!)
The object you are getting must not be a SwiftJSON object. Here's playground code that works perfectly (requires SwiftyJSON.swift to be in the Sources folder):
let jsontext = "{\"maxResults\":50,\"startAt\":0,\"isLast\":true,\"values\":[{\"id\":1,\"self\":\"https://stackrank.atlassian.net/rest/agile/1.0/board/1\",\"name\":\"JI board\",\"type\":\"scrum\"},{\"id\":2,\"self\":\"https://stackrank.atlassian.net/rest/agile/1.0/board/2\",\"name\":\"Board2\",\"type\":\"scrum\"}]}"
let data = jsontext.data(using: .utf8)!
let json = JSON(data)
print(json["maxResults"].intValue)
print(json["values"].arrayValue)
This works perfectly.
In terms of the raw data, here's what another SO question proposed:
Alamofire.request(.GET, url).validate().responseJSON { response in
switch response.result {
case .Success(let data):
let json = JSON(data)
let maxResults = json["maxResults"].intValue
let values = json["values"].arrayValue
print(maxResults)
case .Failure(let error):
print("Request failed with error: \(error)")
}
}

How to convert <AnyObject> response in AnyObject after an Alamofire request with JSON in Swift?

So I want to send a request to a specific API which is supposed to return a JSON file.
I am using Alamofire in order to get the JSON object :
dataFromAPI : JSON
Alamofire.request(.GET, myURL).responseJSON { (_, _, data) -> Void in
dataFromAPI = JSON(data)
}
My problem is that data is an array of AnyObject and the JSON function needs an AnyObject type. How can I transform one into another or resolve the problem ?
Not sure if I got your question, but will try to provide you an example of how I do it.
Changed code to your case.
Alamofire.request(.GET, myURL)
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseJSON { request, response, jsonResult in
switch jsonResult {
case .Success:
if let data = jsonResult.value as? AnyObject {
self.dataFromAPI = JSON(data)
}
case .Failure(_, let error):
print(error)
}
}
Normally I wouldn't do unwrapping to AnyObject, as it makes little sense.
I usually unwrap to [String: AnyObject] as I'm expecting Dictionary from my API, and then I attempt to convert it to my custom model class.
Correct me if I miss-understood the question. :)
Alamofire returns a Result<AnyObject> object. You should check if the result is a success or a failure before extracting the JSON:
Alamofire.request(.GET, myURL)
.responseJSON { request, response, result in
switch result {
case .Success(let JSON):
print("Success with JSON: \(JSON)")
case .Failure(let data, let error):
print("Request failed with error: \(error)")
if let data = data {
print("Response data: \(NSString(data: data, encoding: NSUTF8StringEncoding)!)")
}
}
}