I am attempting to access the open secret API (https://www.opensecrets.org/api) from a swift created iPhone App.
I am using AFNetworking GET request as follows:
func getContributors(congressperson: congressPerson!, success: ([NSDictionary]) -> (), failure: (NSError) -> ()){
let parameters = [
"cid": congressperson.crpId,
"output": "json",
"apikey": opensecretApiKey,
"cycle": "2016"] as NSDictionary
GET("api/?method=candContrib", parameters: parameters, progress: nil, success: { (operation: NSURLSessionDataTask, response: AnyObject?) -> Void in
let results = response!["results"] as! [NSDictionary]
print("here success")
success(results)
}) { (operation: NSURLSessionDataTask?, error: NSError) -> Void in
print("here fail")
failure(error)
}
}
Although I am requesting an output of json, this code results in the error:
Request failed: unacceptable content-type: text/html
Am I doing something wrong in this request? Anyone know how to force it to return as json?
Related
I'm calling an Api route to get branches of a local store using longitude, latitude & radius. The api route is working just fine on postman. Using Alamofire it is replying internal server error 500. I doubt the issue is in the parameters but i just tested everything and every combination with no success.
Here is my HTTP request:
let branchesRoute = "geo/services/"
//Get branches within location radius
func getBranchesWithRadius (serviceID: Int, location: CLLocation, completion: #escaping (_ status:Bool, _ error:Error?, _ msg:String?, _ branches:NSArray?) ->())
{
let route = URL(string:branchIp + branchesRoute + String(serviceID) + "/branches")
print(route)
let header: HTTPHeaders = [
"Content-Type":"application/json",
"auth-token": Helper.shared.getApiKey()//"\(Helper.shared.getApiKey())"
]
let params: Parameters = [
"longitude" : location.coordinate.longitude,
"latitude" : location.coordinate.latitude,
"radius" : Helper.shared.getRadius()
]
print(params)
Alamofire.request(route!, method: .get, parameters: params, encoding: JSONEncoding.default, headers: header)
.validate(statusCode: 200..<300)
.responseJSON { (response) in
switch response.result {
case .success( _):
let json = response.result.value!
// let swiftyJson = JSON(json)
completion(true, nil, nil, json as? NSArray)
// print(json)
case .failure(let err):
print(err)
if response.response?.statusCode == 401 {
completion(false,err,"Unauthorized",nil)
} else {
completion(false, err, "Error getting branches",nil)
}
}
}
}
This is the route im calling from postman:
http://100.100.70.185:9090/geo/services/3/branches?longitude=31.331358000000002&latitude=30.082763&radius=1000000
When i used print() command in swift these were my results:
print(params) = ["longitude": 31.331358000000002, "latitude": 30.082763, "radius": 100000]
print(route) =
Optional(http://100.100.70.185:9090/geo/services/3/branches)
Regarding the Optional i'm just unwrapping it route!
Regarding the ip address i wrote here are not the real ones that i use in case you tested and it didn't work out.
The actual issue is in encoding and you have to use the correct ParameterEncoding depending on your API implementation.
Use URLEncoding if the Content-Type HTTP header field of an encoded request with HTTP body is set to application/x-www-form-urlencoded; charset=utf-8
-
Use JSONEncoding if the Content-Type HTTP header field of an
encoded request is set to application/json
-
Use PropertyListEncoding if the Content-Type HTTP header field of
an encoded request is set to application/x-plist
I am using Alamofire and SwiftyJSON to call and API and get back a JSON response. I am then using:
let responseJSON = JSON(response.result.value!)
let userDataJSON = responseJSON["userData"]
Sync.changes(
userDataJSON,
inEntityNamed: "User",
dataStack: self.appDelegate.dataStack,
completion: { (response ) -> Void in
print("User \(response)")
})
to try to Sync the response to Core Data using Hyperoslo Sync but I am getting an error
Cannot convert value of type 'JSON' to expected argument type '[AnyObject]!'
Thanks
EDIT
Alamofire.request(Router.AuthenticateUser(postParameters))
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseJSON { response in
if response.result.isSuccess {
let responseJSON = JSON(response.result.value!)
if let userDataJSON = responseJSON["userData"] {
Sync.changes(
[userDataJSON],
inEntityNamed: "User",
dataStack: self.appDelegate.dataStack,
completion: { (response ) -> Void in
print("User \(response)")
})
}
...
Initializer for conditional binding must have Optional type, not 'JSON'
As per documentation Sync.changes syntax:
Sync.changes(
changes: [AnyObject]!,
inEntityNamed: String!,
dataStack: DATAStack!,
completion: ((NSError!) -> Void)!)
It expect array of AnyObject, and you are passing just userDataJSON which is not an array so pass it like [userDataJSON].
Also check if userDataJSON is an optional then either safely unwrap using if let or force unwrap using ([userDataJSON]!).
So try,
Sync.changes(
[userDataJSON]!,
inEntityNamed: "User",
dataStack: self.appDelegate.dataStack,
completion: { (response ) -> Void in
print("User \(response)")
})
or
if let userDataJSON = responseJSON["userData"] {
Sync.changes(
[userDataJSON],
inEntityNamed: "User",
dataStack: self.appDelegate.dataStack,
completion: { (response ) -> Void in
print("User \(response)")
})
}
I'm using SwifyJSON to parse some JSON sent to my iOS app through socket.io and the .dictionaryValue of the response is nil. Here's how the data is sent from the server:
socket.emit('hasBeenMatched', {user: JSON.stringify(currentUser)});
Here's what I've got in my iOS app:
socket.on("hasBeenMatched", callback: {data, ack in
println("got response after requesting match");
let user = JSON(data!)
println(user)
println(user[0])
println(user[0]["user"])
println(user[0]["user"].dictionaryValue)
})
And here's the output of that code:
got response after requesting match
[
{
"user" : "{\"_id\":\"5511c3d8abcdc2fcf7b8fe4b\",\"email\":\"j\",\"password\":null,\"firstname\":\"j\",\"lastname\":\"j\",\"age\":9,\"radius\":\"9\",\"__v\":0,\"wantsToBeMatched\":true,\"matchedWith\":\"k k\"}"
}
]
{
"user" : "{\"_id\":\"5511c3d8abcdc2fcf7b8fe4b\",\"email\":\"j\",\"password\":null,\"firstname\":\"j\",\"lastname\":\"j\",\"age\":9,\"radius\":\"9\",\"__v\":0,\"wantsToBeMatched\":true,\"matchedWith\":\"k k\"}"
}
{"_id":"5511c3d8abcdc2fcf7b8fe4b","email":"j","password":null,"firstname":"j","lastname":"j","age":9,"radius":"9","__v":0,"wantsToBeMatched":true,"matchedWith":"k k"}
[:]
In an alternate part of my code I have the following code:
let request = Alamofire.request(.POST, "http://localhost:3000/api/users/authenticate", parameters: params)
request.validate()
request.response { [weak self] request, response, data, error in
if let strongSelf = self {
// Handle various error cases here....
var serializationError: NSError?
if let json: AnyObject = NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments, error: &serializationError) {
println(JSON(json).dictionaryValue)
// Story board navigation
} else {
//Handle error case
}
}
}
EDIT: the output of the println in the Alamofire response handling looks like:
[_id: 5511c3d8abcdc2fcf7b8fe4b, password: null, __v: 0, lastname: j, age: 9, wantsToBeMatched: true, firstname: j, radius: 9, email: j, matchedWith: k k]
What I'm wondering is: why does println(user[0]["user"].dictionaryValue) result in [:]?
Figured it out, but my solution isn't related to SwiftyJSON (which I'm still curious about). I changed how my server sends data over socket. I changed socket.emit('hasBeenMatched', {user: JSON.stringify(currentUser)}); to socket.emit('hasBeenMatched', {user: currentUser});. Essentially, I removed the manual JSON-ification.
I tried to use "Yoda Speak" API by Mashape in Swift.
I will print the data from the API.
I succeeded calling "response" method after "getData" method but my simulator is out in the "response" method.
I know there're some similar questions, but I couldn't.
Please give me some advices.
func response(res: NSURLResponse!, data: NSData!, error: NSError!) {
println("response")
if error != nil {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
} else {
println("succeeded")
}
// simulator is out here.
var json: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
for value in json {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
println(value)
})
}
}
func getData() {
println("getData")
// URL.
let url = NSURL(string: "https://yoda.p.mashape.com/yoda?sentence=You+will+learn+how+to+speak+like+me+someday.++Oh+wait.")!
// URLRequest.
var req = NSMutableURLRequest(URL: url)
// header.
req.setValue("jY0bEhHCBpmsh8j1mpA5p11tCJGyp1tok3Zjsn4ubbvNNp5Jt3", forHTTPHeaderField: "X-Mashape-Key")
let connection: NSURLConnection = NSURLConnection(request: req, delegate: self, startImmediately: false)!
// Connection to the server.
NSURLConnection.sendAsynchronousRequest(req, queue: NSOperationQueue.mainQueue(), completionHandler: self.response)
println("complete")
}
I would give Alamofire a try. I know this also works well with SwiftyJSON. There is a great example on the GitHub page on how to request/receive a response with Alamofire.
I want to make a GET request in swift to get some Json data.
I tried to use AFNetworking and it works, but I don't know how to return the Json I get.
I tried with a return but it's made before the GET so I get nothing...
func makeGet(place:String) -> String
{
var str:String = ""
let manager = AFHTTPRequestOperationManager()
manager.requestSerializer.setValue("608c6c08443c6d933576b90966b727358d0066b4", forHTTPHeaderField: "X-Auth-Token")
manager.GET("http://something.com/api/\(place)",
parameters: nil,
success: { (operation: AFHTTPRequestOperation!,responseObject: AnyObject!) in
str = "JSON: \(responseObject.description)"
println(str) //print the good thing
},
failure: { (operation: AFHTTPRequestOperation!,error: NSError!) in
str = "Error: \(error.localizedDescription)"
})
return str //return ""
}
Can you help me ?
Since you want to return the value after the webservice request is completed you have to pass the data via a delegate or a block(In swift it is called closures)
I see blocks useful here
//Above your class file create a handler alias
typealias SomeHandler = (String! , Bool!) -> Void
func makeGet(place:String , completionHandler: SomeHandler!)
{
var str:String = ""
let manager = AFHTTPRequestOperationManager()
manager.requestSerializer.setValue("608c6c08443c6d933576b90966b727358d0066b4", forHTTPHeaderField: "X-Auth-Token")
manager.GET("http://something.com/api/\(place)",
parameters: nil,
success: { (operation: AFHTTPRequestOperation!,responseObject: AnyObject!) in
str = "JSON: \(responseObject.description)"
println(str) //print the good thing
completionHandler(str,false) //str as response json, false as error value
},
failure: { (operation: AFHTTPRequestOperation!,error: NSError!) in
str = "Error: \(error.localizedDescription)"
completionHandler("Error",true)
})
//return str //return "" You don't want to return anything here
}
When you want to call the method get the values like this
makeGet(){
yourJSONString , errorValue in //Here the value will be passed after you get the response
if !errorValue {
println("The End."
}
}
More about swift closures
FYI: AFNetworking owner has created a new Networking layer for swift and it is called Alamofire (AF from AFNetworking is Alamofire :])
You're not getting a response from that function, because the GET operation happens asynchronously. That is, the order of execution looks like this:
You call makeGet
makeGet creates manager, which fires off a GET request
makeGet finishes executing and returns an empty string
(some time later) manager receives a value back from the server and executes either the success or failure block.
So the only time you have access to the JSON that comes back from the server is in step 4, and you need to find a way of storing that value so you can parse it or use it or whatever. There are a variety of options here -- one is to define closures that call event handlers on your class instance, like this:
class MyClass {
func jsonLoaded(json: String) {
println("JSON: \(json)")
}
func jsonFailed(error: NSError) {
println("Error: \(error.localizedDescription)")
}
func makeGet(place:String) {
let manager = AFHTTPRequestOperationManager()
manager.requestSerializer.setValue("608c6c08443c6d933576b90966b727358d0066b4", forHTTPHeaderField: "X-Auth-Token")
manager.GET("http://something.com/api/\(place)",
parameters: nil,
success: { (operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
self.jsonLoaded(responseObject.description)
},
failure: { (operation: AFHTTPRequestOperation!, error: NSError!) in
self.jsonFailed(error)
}
)
}
}
let manager = AFHTTPSessionManager()
manager.GET("http://api.androidhive.info/json/movies.json", parameters: nil, success: { (operation, responseObject) -> Void in
print(responseObject)
}, failure: nil)
AFHTTPRequestOperationManager is not available in latest AFnetworking library, it has replaced with AFHTTPSessionManager.
This is a simple example of getting response object.