I'm trying to make a Get request with Alamofire for swift. When I run in Simulator or device with iOS 10 it works fine. When I run my app on Devices with iOS 9.x or prior, I'm getting "cannot parse response". The JSON response is right. I checked in postman.
There's my code:
lass func getStores(latitude:Float, longitude: Float, completion : #escaping (Array<Store>?, NSError?) -> ()) {
let latString: String = "\(latitude)"
let lonString: String = "\(longitude)"
var listStores: Array<Store> = []
let urlFull : String = ConstantHelper.kUrlStore
Alamofire.request(urlFull, method: .get, parameters: ["latitude":latString, "longitude": lonString], encoding: JSONEncoding(options: []), headers: [:]).validate()
.responseJSON { response in
switch response.result {
case .success:
if let repoJSON = response.result.value {
print(repoJSON)
let jsonArray = repoJSON as! NSArray
for item in jsonArray {
guard let store = Store(json: item as! JSON) else
{
print("Issue deserializing model")
return
}
listStores.append(store)
}
completion(listStores, nil)
}
break
case .failure(let error):
completion(nil, error as NSError?)
break
}
}
}
}
I solved my problem with the following code without JSON enconding in request:
Alamofire.request(urlFull, method: .get, parameters: ["latitude":latString, "longitude": lonString]).validate()
I don't know why works in Swift 2.x and in Swift 3.0 with iOS 10 with encoding and don't in ios 9...but the code above works in all situations. And its really no needed to enconding this request
Related
I am using Alamofire to get DataResponse value for a GET request. But I am getting following JSON which I am unable to understand why
SUCCESS: {
data = (
{
"alt_text" = " ....
}
);
meta = {
};
links = {
};
}
I am unable to understand this JSON format
The snippet your posted is not the JSON you want from alamofire, the SUCCESS is just telling you that the request is successful, and you get your actual data by unwrapping it.
I assume the snippet you posted is your response, here's an example:
AF.request(url, method: .get, parameters: [])
.validate(statusCode: 200..<300)
.responseJSON() { response in
switch response.result {
case .success(let json):
guard let dictJson = json as? [String : Any],
let dataDict = dictJson["data"] as? [String : Any] else { return }
// Handle your json here
print(dataDict)
case .failure(let err):
// Your error handling goes here
}
}
I'm building a network stack using Alamofire 4 and Swift 3. Following the Alamofire guidelines I've created a router for the endpoints of the services. I'm currently using the free API of OpenWeatherMap but I'm finding problems in order to create a get request.
That's the url needed: http://api.openweathermap.org/data/2.5/weather?q=Rome&APPID=MY_API_KEY. Pasted on a browser, and using a real API Key it works and gives me back my nice json full of info about the weather in the given location.
On my App I can insert the parameters as Dictionary but I cannot find a way to append the api key at the end of the url.
That's my enum router:
enum OWARouter: URLRequestConvertible {
case byCityName(parameters: Parameters)
// MARK: Url
static let baseURLString = "http://api.openweathermap.org"
static let apiKey = "MY_APY_KEY"
static let pathApiKey = "&APPID=\(apiKey)"
var method: HTTPMethod {
switch self {
case .byCityName:
return .get
}
}
var path: String {
switch self {
case .byCityName:
return "/data/2.5/weather"
}
}
// MARK: URLRequestConvertible
func asURLRequest() throws -> URLRequest {
let url = try OWARouter.baseURLString.asURL()
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
switch self {
case .byCityName(let parameters):
urlRequest = try URLEncoding.default.encode(urlRequest, with: parameters)
print((urlRequest.url)!)
}
urlRequest.httpMethod = method.rawValue
return urlRequest
}
}
When I log my (urlRequest.url)! I have this: http://api.openweathermap.org/data/2.5/weather?q=Rome but I cannot find a way to add the apiKey.
What am I doing wrong?
I've also made an ugly test adding this code after the print:
var urlRequest2 = URLRequest(url: (urlRequest.url)!.appendingPathComponent(OWARouter.pathApiKey))
print("URL2: \(urlRequest2)")
And the log is URL2: http://api.openweathermap.org/data/2.5/weather/&APPID=My_API_KEY?q=Rome
How come the api key is in the middle?
If you need this is the simple request code:
Alamofire.request(OWARouter.byCityName(parameters: ["q":"Rome"])).responseJSON { response in
print(response.request)
print(response.response)
print(response.data)
print(response.result)
debugPrint(response)
if let JSON = response.result.value {
print("json: \(JSON)")
}
}
Another question...
If I use as parameters ["q":"Rome, IT"], my output url is: http://api.openweathermap.org/data/2.5/weather?q=Rome%2CIT
How to keep the comma?
Thank you!
Swift - 5 Alamofire 5.0 Updated Code (just Change AF.request Method according to your requirement you can add Parameters headers and intercepter as well )
Alamofire.request(url, method: .get, encoding: JSONEncoding.default)
.responseJSON { response in
switch response.result {
case .success(let json):
print(json)
DispatchQueue.main.async {
// handle your code
}
case .failure(let error):
print(error)
}
}
Used below lines of code:
func getRequestAPICall(parameters_name: String) {
let todosEndpoint: String = "your_server_url" + "parameterName=\(parameters_name)"
Alamofire.request(todosEndpoint, method: .get, encoding: JSONEncoding.default)
.responseJSON { response in
debugPrint(response)
if let data = response.result.value{
// Response type-1
if (data as? [[String : AnyObject]]) != nil{
print("data_1: \(data)")
}
// Response type-2
if (data as? [String : AnyObject]) != nil{
print("data_2: \(data)")
}
}
}
}
func AlamofireGetCode()
{
var url:String!
url = "https://jsonplaceholder.typicode.com/comments"
Alamofire.request(url, method: .get, encoding: JSONEncoding.default)
.responseJSON { response in
switch response.result{
case .success(let json):
print(json)
DispatchQueue.main.async {
print(json)
self.mainarray = json as? NSArray
print(self.mainarray as Any)
self.mytableviewreload.reloadData()
}
case .failure(let error):
print(error)
}
}
}
I've found a solution... the Api Key is simply a parameter to send to the request. So the code to change is not in the router but in the request function:
Alamofire.request(OWARouter.byCityName(parameters: ["q":"Rome","APPID":"MY_API_KEY"])).responseJSON { response in
print(response.request)
//print(response.response)
//print(response.data)
//print(response.result)
//debugPrint(response)
if let JSON = response.result.value {
print("json: \(JSON)")
}
}
EDIT: the comma issue do not gives me any problem now. Thank you.
Swift 5+
Use AF.request
let todosEndpoint: String = "https://jsonplaceholder.typicode.com/todos/1"
let request = AF.request(todosEndpoint)
request.responseJSON { (data) in
print("Response", data)
}
**//
Fist in third party liabrary, install pod 'Alamofire'
Using Alamofire get json data
import UIKit
import Alamofire
class APIWRAPPER: NSObject {
static let instance = APIWRAPPER()
func LoginAPI(Uname : String , Password : String) {
let requestString =
"http://************php/v1/sign-in"
let params = ["user_name": Uname,
"password": Password]
Alamofire.request(requestString,method: .get, parameters: params, encoding: JSONEncoding.prettyPrinted, headers: [:]).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if response.result.value != nil
{
print("response : \(response.result.value!)")
}
else
{
print("Error")
}
break
case .failure(_):
print("Failure : \(response.result.error!)")
break
}
}
}
}
I am using AFNetworking with Swift 3.0 and I am stuck on one code.
func getJSON()
{
let manager = AFHTTPSessionManager()
manager.get(
url,
parameters: nil,
success:
{
(operation: URLSessionTask!, responseObject: Any?) in
print("JSON: " + responseObject!.description)
self.matchesArray = responseObject!.object(forKey: "matches")! as? NSMutableArray
self.tollBothPlazaTableView.reloadData()
},
failure:
{
(operation: URLSessionTask!, error: NSError) in
print("Error: " + error.localizedDescription)
}
)
}
It shows error on failure block.
Cannot convert value of type '(URLSessionTask!, NSError) -> ()' to expected argument type '((URLSessionDataTask?, Error) -> Void)?'`
Can someone explain what is wrong in my code. Also the correct way to use closures? (I am new to swift).
Error is clearly saying that use Error instead of NSError, in Swift 3 you need to use Error instead of NSError. So change your code like below.
func getJSON() {
let manager = AFHTTPSessionManager()
manager.get(
url,
parameters: nil,
success:
{
(operation, responseObject) in
if let dic = responseObject as? [String: Any], let matches = dic["matches"] as? [[String: Any]] {
print(matches)
}
DispatchQueue.main.async {
self.tollBothPlazaTableView.reloadData()
}
},
failure:
{
(operation, error) in
print("Error: " + error.localizedDescription)
})
}
Note: Always perform UI changes on main thread when you are on background thread, so batter to reload your tableView on main thread like I have done, Also use Swift native Array and Dictionary instead of NSArray and NSDictionary.
**Its Better to use Alamofire(same developer) in swift 3 **
func jsonRequest()
{
let url = "url"
//if you want to add paramter
parametr = ["username" : "user" , "password"]
Alamofire.request(url, method: .post, parameters: nil, encoding: JSONEncoding.default)
.responseJSON { response in
// print(response)
//to get status code
if let status = response.response?.statusCode {
switch(status){
case 201:
print("example success")
default:
print("error with response status: \(status)")
}
}
//to get JSON return value
if let array = response.result.value as? //NSDictionary [[String : Any]]
{
}
}
}
I'm developing an iOS app which user WebServices and I find Alamofire just perfect for what I'm doing but I'm having a problem; the app asks the user to login which is an Alamofire call and does it just fine.
The problem is, it has to create a collection view based on the content of another Alamofire request but is always nil.
func getJSON(URLToRequest: String) -> JSON {
let comp:String = (prefs.valueForKey("COMPANY") as? String)!
let params = ["company":comp]
var json:JSON!
let request = Alamofire.request(.POST, URLToRequest, parameters: params).responseJSON {
response in
switch response.result {
case .Success:
if let value = response.result.value {
json = JSON(value)
}
default:
json = JSON("");
}
}
debugPrint(request.response)
return json;
}
The same codeblock works perfect for the Login but doesn't in this case BTW the debug Print always print nil
You're trying to access to request.response before it has been set, remember that Alamofire works asynchronously, so you have to return in your case the JSON using closures, but remember that Alamofire also returns an error, so I strongly recommend use the following code instead:
func getJSON(URLToRequest: String, completionHandler: (inner: () throws -> JSON?) -> ()) {
let comp:String = (prefs.valueForKey("COMPANY") as? String)!
let params = ["company":comp]
let request = Alamofire.request(.POST, URLToRequest, parameters: params).responseJSON {
response in
// JSON to return
var json : JSON?
switch response.result {
case .Success:
if let value = response.result.value {
json = JSON(value)
}
completionHandler(inner: { return json })
case .Failure(let error):
completionHandler(inner: { throw error })
}
}
The trick is that the getJSON function takes an additional closure called 'inner' of the type () throws -> JSON?. This closure will either provide the result of the computation, or it will throw. The closure itself is being constructed during the computation by one of two means:
In case of an error: inner: {throw error}
In case of success: inner: {return json}
And then you can call it like in this way:
self.getJSON("urlTORequest") { (inner: () throws -> JSON?) -> Void in
do {
let result = try inner()
} catch let error {
print(error)
}
}
I hope this help you.
I have a question about the new version of Alamofire for Swift 2
Alamofire.request(.POST, urlString, parameters: parameters as? [String : AnyObject])
.responseJSON { (request, response, result) -> Void in
let dico = result as? NSDictionary
for (index, value) in dico! {
print("index : \(index) value : \(value)")
}
}
In this section I would like to cast the result in to a NSDictionary. But When I compile and put a breakpoint, the debugger says that dico is nil. If I use debugDescription to print result, it is not nil and contains what I expected
How can I cast the Result variable?
The accepted answer works great but with the introduction of Alamofire 3.0.0 there are some breaking changes that affects this implementation.
The migration guide has further explanations but i will highlight the ones related to the actual solution.
Response
All response serializers (with the exception of response) return a generic Response struct.
Response type
The Result type has been redesigned to be a double generic type that does not store the NSData? in the .Failure case.
Also take in count that Alamofire treats any completed request to be successful, regardless of the content of the response. So you need to chain a .validate() before .responseJSON() to hit the .Failure case.
Read more about it here.
Updated code:
let url = "http://api.myawesomeapp.com"
Alamofire.request(.GET, url).validate().responseJSON { response in
switch response.result {
case .Success(let data):
let json = JSON(data)
let name = json["name"].stringValue
print(name)
case .Failure(let error):
print("Request failed with error: \(error)")
}
}
For reference:
Xcode 7.3 (Swift 2.2)
Alamofire 3.3.1
SwiftyJSON 2.3.3
If you don't mind using SwiftyJSON library, here's a working example in Xcode 7 Beta 5 + Alamofire 2.0.0-beta.1 + SwiftyJSON (xcode7 branch)
Alamofire.request(.GET, url, parameters: params, encoding: ParameterEncoding.URL).responseJSON { (_, _, result) in
switch result {
case .Success(let data):
let json = JSON(data)
let name = json["name"].string
case .Failure(_, let error):
print("Request failed with error: \(error)")
}
}
Edit:
Updated SwiftyJSON git page
You can now achieve most of the required behaviour out of the box without the need for SwiftyJSON for example. My OAuthTokenResponse is a simple struct that is Codable. The Alamofire library 5.2.2 lets you respond using the 'responseDecodable'
If you have say a struct that looks like this:
struct OAuthTokenResponse : Codable
{
var access_token:String?
var token_type:String?
var expires_in:Int?
var scope:String?
}
And then in your network call (using Alamofire)
let request = AF.request(identityUrl, method: .post, parameters: parameters, encoding: URLEncoding.httpBody)
request
.validate()
.responseDecodable { (response:AFDataResponse<OAuthTokenResponse>) in
switch response.result {
case .success(let data):
do {
let jwt = try decode(jwt: data.access_token!) // example
self.connected = true
print(jwt)
} catch {
print(error.localizedDescription)
self.connected = false
}
case .failure(let error):
self.connected = false
print(error.localizedDescription)
}
}
In the above code, the success case automatically deserialises your JSON using the decodable protocol into your struct. Any errors will result in the error case being hit instead.