Swift get request returning unauthorised - swift

I'm using a get request to request data from predicthq, for some reason I keep receiving a response of {"error": "unauthorized"} as the JSON response. I've changed the API a few times now with no luck. I have tried it within Postman and the data is getting returned...
This is the python example they provide:
response = requests.get(
url="https://api.predicthq.com/v1/events",
headers={
"Authorization": "Bearer $ACCESS_TOKEN",
"Accept": "application/json"
}
)
This is the request I'm using, the API key is 100% correct as I've used it to make a request on their website:
let url = URL(string: "https://api.predicthq.com/v1/events")
guard let requestUrl = url else { fatalError() }
// Create URL Request
var request = URLRequest(url: requestUrl)
// Headers
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Accept")
// Specify HTTP Method to use
request.httpMethod = "GET"
// Send HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check if Error took place
if let error = error {
print("Error took place \(error)")
return
}
// Read HTTP Response Status code
if let response = response as? HTTPURLResponse {
print("Response HTTP Status code: \(response.statusCode)")
}
// Convert HTTP Response Data to a simple String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
}
}
task.resume()
Edit: I have also tried using AlamoFire with the same result.
let path = "https://api.predicthq.com/v1/events"
let headers: HTTPHeaders = ["Authorization": "Bearer \(token)"]
AF.request(path, method: .get, headers: headers)
.responseJSON { (response) in
if let data = response.data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
}
}

Okay, the issue has been identified. "https://api.predicthq.com/v1/events" needs a / at the end and it works fine.

Related

Swift POST to api

I have an odd issue and I am hoping you guys can help me.
The Task:
I want to post json to a API rest call.
And I am sure the rest API works - I have copied the json from print() in Swift and tried it in postman, and the works just fine.
When I try to post via Swift i get 400 Bad request.
The code:
func postMobileContacts(serverURL: String, jsonToPost: String){
// Prepare URL
let url = URL(string: serverURL)
guard let requestUrl = url else { fatalError() }
// Prepare URL Request Object
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
// Set HTTP Request Body
request.httpBody = Data(jsonToPost.utf8);
// Set HTTP Request Header
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Authorization", forHTTPHeaderField: String(data: KeychainHelper.standard.read(service: "access-token", account: "store")!, encoding: .utf8)!)
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check for Error
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
}
}
task.resume()
}
This line is definitely wrong:
request.setValue("Authorization", forHTTPHeaderField: String(data: KeychainHelper.standard.read(service: "access-token", account: "store")!, encoding: .utf8)!)
it should be the other way around.
request.setValue(String(data: KeychainHelper.standard.read(service: "access-token", account: "store")!, encoding: .utf8)!, forHTTPHeaderField: "Authorization")
You mixed up the value with the header name.
Made some edits to your code
Currently the data is not directly sent to the request as said in comments.
JSONEncodable can be send to the request after encoding to data.
func postMobileContacts(serverURL: String, jsonToPost: Encodable) { //<--here
// Prepare URL
let url = URL(string: serverURL)
guard let requestUrl = url else { fatalError() }
let data = try! JSONEncoder().encode(jsonToPost) //<-Changed here
// Prepare URL Request Object
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
// Set HTTP Request Body
request.httpBody = data; //<-- and here
// Set HTTP Request Header
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Authorization", forHTTPHeaderField: String(data: KeychainHelper.standard.read(service: "access-token", account: "store")!, encoding: .utf8)!)
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check for Error
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
}
}
task.resume()
}

How can I read the content of a form-data when the response is in html(Swift)

I'm building an iOS application and I need to access the information on a website. I've located the API endpoint, and was able to get a result in Postman
screenshot of API header and form data
So far I have this code which can allow me to make the request, but how do I parse the response(which is an HTML form, then display response in app
var urlRequest = URLRequest(url: url!)
urlRequest.setValue("application/form-data",forHTTPHeaderField: "Content-Type")
urlRequest.httpMethod = "POST"
let postString = "year=2021&season=Outdoor&province=ON&age_group=OPEN&age_sub_group_masters=ALL&age_sub_group_para=ALL&rankings_event=100m&best_by_athlete=1&rankings_event_spec_num=1&is_relay_EVENT=0&page=1"
urlRequest.httpBody = postString.data(using: .utf8)
urlRequest = .init(url: url!)```
I actually found a great resources that showed how to send POST Request with post body, and how to read the response
How To send POST Request
Now it's just a matter of parsing the HTML that is returned, and displaying it in app.
let url = URL(string: Constants.rankingAPI)
guard let requestUrl = url else {
fatalError()
}
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
let postString = "year=2021&season=Outdoor&province=ON&age_group=OPEN&age_sub_group_masters=ALL&age_sub_group_para=ALL&rankings_event=100m&best_by_athlete=1&rankings_event_spec_num=1&is_relay_EVENT=0&page=1"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check for Error
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString.htmlToString)")
}
}
task.resume()
}

Swift API call with URLSession gives 504 error

I have an API call with oauth which I tested with correct authorization token in postman.I am getting proper response in postman. But when I try same thing in Swift, I get 504 error.
I have checked every params and headers properly and everything looks same as postman. Not sure why samething is working in postman and gives 504 error in swift. what could be issue?
var params = [String : String]()
params["Id"] = Id;
var headers = [String : String]()
headers["api-key"] = "XXXXXX"
headers["Authorization"] = "Bearer XXX"
do{
var request = URLRequest(url: URL(string: getURL())!)
request.allHTTPHeaderFields = headers
request.httpBody = try JSONSerialization.data(withJSONObject: params , options: [])
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
let httpResponse = response as! HTTPURLResponse
print(httpResponse)
}
task.resume()
}catch{
}
When using a GET request, there is no body to the request. Everything goes on the URL.
Also are you sure that in Postman you are using only those 2 headers?
See if something like this works for you:
var params: Parameters = Parameters()
params.updateValue(Id, forKey: "Id")
var components = URLComponents(string: getURL())!
components.queryItems = params.map { (key, value) in
URLQueryItem(name: key, value: value)
}
components.percentEncodedQuery = components.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
let request = URLRequest(url: components.url!)
request.setValue("XXXXXX", forHTTPHeaderField: "api-key")
request.setValue("Bearer XXX", forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
}
task.resume()

Translating Alamofire call to URLSession

I've got a old codebase that I'm trying to migrate out of. The network calls currently use Alamofire 4.0 and I'm trying to use URLSession instead. I'm having trouble figuring out what's wrong, here's what I've been doing. I start off with the route and params that I want to post:
// route to user creation
let url = ...
let params = ["user": ["first_name": "John", "last_name": "Appleseed", "email": "john#apple.com", "password": "asdfgh"]]
Here's the old and new network calls:
// old network request
Alamofire.request(url, method: .post, parameters: newUser, encoding: JSONEncoding.default).responseJSON { response in
// ...
}
// new code
var request = URLRequest(url: url)
let jsonData = try! JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
request.httpBody = jsonData
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { return print("error=\(error)") }
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("status code should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
}
task.resume()
For some reason, I'm getting a status code of 400 in my URLSession attempt. Alamofire works fine.
Any advice appreciated.
The problem is that the request isn't recognized as a JSON call. Write the following assignment after you create your URLRequest:
request.allHTTPHeaderFields = ["Content-Type": "application/json"]

NSURLSession parameters not recognized

Im attemping to make a HTTPRequest using NSURLSession. When I set the full url the request returns the correct data but when using parameters (NSJSONSerialization.dataWithJSONObject -> HTTPBody I get this error
error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."
is there something im doing wrong here?
let json = ["api_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"]
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(json, options: .PrettyPrinted)
let url = NSURL(string: "https://api.themoviedb.org/3/discover/movie")!
let request = NSMutableURLRequest(URL: url)
request.HTTPBody = jsonData
request.HTTPMethod = "GET"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data, response, error in
if error != nil{
print("Error -> \(error)")
return
}
do {
let result = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String:AnyObject]
print("Result -> \(result)")
} catch {
print("Error -> \(error)")
}
}
task.resume()
} catch {
print(error)
}
}
This is not a duplicate! I looked at the suggested answer (none of them worked) before asking this question
In your case that issue can be solved by changing the request.HTTPMethod = "GET" to request.HTTPMethod = "POST"
You should not send HTTP Body in the get request, to send the data with the body you should change HTTPMethod to post
Note: Please check if this api method supports POST requests, if it don't support post you can't use it with http body/post, as per doc i only find 'get' request for the discover/movie which can be like this:
let url = NSURL(string: "http://api.themoviedb.org/3/discover/movie?api_key=YOUR_API_KEY")!
let request = NSMutableURLRequest(URL: url)
request.addValue("application/json", forHTTPHeaderField: "Accept")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { data, response, error in
if let response = response, data = data {
print(response)
print(String(data: data, encoding: NSUTF8StringEncoding))
} else {
print(error)
}
}
task.resume()
Ref: You can check more information from this url: http://docs.themoviedb.apiary.io/#reference/discover/discovermovie/get