How to download the file from Parse.com using the REST API? - ios

I found this question at Parse.com file download question, however, it only mentions that the file can be downloaded from the Url. Also, the Parse.com REST Documentation only discuss upload file and associated with an Object.
I tried to access the URL only, but it returns an error.
Can anyone help with an example in Swift and using the REST API, how to download the actual file once you get the URL after querying the object?
This is the error I get:
Error Domain=NSURLErrorDomain Code=-1100 "The requested URL was not found on this server." UserInfo={NSUnderlyingError=0x7fa39940dcc0 {Error Domain=kCFErrorDomainCFNetwork Code=-1100 "(null)"}
This is my code in Swift 2.0:
func downloadFile(){
let str = "http://files.parsetfss.com/c426b506-44da-447d-91d0-93f13980758b/tfss-127e50c4-be6e-4228-b1a3-3f253358ac24-pic.jpg"
let request = NSMutableURLRequest()
request.HTTPMethod = "GET"
request.addValue(appID, forHTTPHeaderField: "X-Parse-Application-Id")
request.addValue(apiKey, forHTTPHeaderField: "X-Parse-REST-API-Key")
let url = NSURL(fileURLWithPath: str)
request.URL = url
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {
(data, response, error) in
if (error == nil) {
do {
let image = try NSJSONSerialization.dataWithJSONObject(data!, options: [])
} catch {
}
}
})
task.resume()
}
This is the JSON response I get when I query the object, and the url is what needs to be used in order to get the file:
"picture": {
"__type" = File;
name = "tfss-127e50c4-be6e-4228-b1a3-3f253358ac24-pic.jpg";
url = "http://files.parsetfss.com/c426b506-44da-447d-91d0-93f13980758b/tfss-127e50c4-be6e-4228-b1a3-3f253358ac24-pic.jpg";

I bet your problem is in this line:
let url = NSURL(fileURLWithPath: str)
"str" is a remote URL and not a local file path, and what that API is trying to do is create a local "file:///" url from the string you provided it.
Why not do:
let url = NSURL(string: str)
and see if that works better?

Related

How to pass bearer token to make Yelp API call with URLSessoin

U P D A T E D... The function with what works!
I would like to incorporate the yelp api into an app but can't successfully pass my authorization token on the URL string. Do I need to do something to connect the URLRequest to the URLSessoin call and its not using the header? Maybe the key value pairs is wrong? The below function returns:
error = {
code = "TOKEN_MISSING";
description = "An access token must be supplied in order to use this endpoint.";
};
I was able to use postman to get the yelp API call working, but only by clicking the "Header" section on postman and putting in Bearer and then my yelp key. I googled around a bit and found some links that indicate that you can add a header to the URLSession that I assume would work the way postman does but I haven't been able to get it to work.
I know there are some githubs with yelp API repos but I am trying to not install a large set of code that I don't understand into my app, when all I want is the JSON that I can see is coming through on postman. Can anyone help me understand how I would edit code similar to the Here example below so that I can get the Authorization/Bearer that yelp requires?
func getYelp() {
let appSecret = "Bearer <YELP APIKEY>"
let link = "https://api.yelp.com/v3/businesses/search?latitude=37.786882&longitude=-122.399972"
if let url = URL(string: link) {
// Set headers
var request = URLRequest(url: url)
request.setValue("Accept-Language", forHTTPHeaderField: "en-us")
request.setValue(appSecret, forHTTPHeaderField: "Authorization")
print("Attempting to get places around location from Yelp")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
print(error!)
} else {
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject // Added "as anyObject" to fix syntax error in Xcode 8 Beta 6
print("Printing all JSON/n/n//n--------------------------")
print(jsonResult)
print("Printing from results/n/n//n--------------------------")
if let description = ((jsonResult["search"] as? NSDictionary)?["context"] as? NSDictionary)?["href"] as? String {
} else {
print("JSON pull failed/n/n//n--------------------------")
}
} catch {
print("JSON Processing Failed/n/n//n--------------------------")
}
}
}
}
task.resume()
} else {
resultLabel.text = "Couldn't get results from Here"
}
}
You're mixing up between the headers and the url, you need to set your headers correctly
if let url = URL(string: "https://places.cit.api.here.com/places/v1/discover/around?at=37.776169%2C-122.421267&app_id=\(app_id)&app_code=\(app_code)") {
var request = URLRequest(url: url)
// Set headers
request.setValue("Accept-Language", forHTTPHeaderField: "en-us")
request.setValue("Authorization", forHTTPHeaderField: "Bearer " + token // Token here)
print("Attempting to get places around location")
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
// ...
Lets say you have an api with "https://google.com" (this is just an example with fake keys)
and an api key that is "ApiKey: 92927839238293d92d98d98d92".
You would then take this information and do this.
let uri = URL(string:"https://google.com")
if let unwrappedURL = uri {
var request = URLRequest(url: unwrappedURL)request.addValue("92927839238293d92d98d98d92", forHTTPHeaderField: "ApiKey")
let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
// you should put in error handling code, too
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
// HERE'S WHERE YOUR DATA IS
print(json)
} catch {
print(error.localizedDescription)
}
}
}
dataTask.resume()
}
Please remember that you would replace the google.com with your GET address and the APIKey header with your own api key values.
Also, this will print out all the JSON like in PostMan.
If this works for you, then I also have a link on accessing the JSON Objects.

Swift URLSession.shared.dataTask GET Request -1001 returns timeout

Sending a POST request to our NGINX Server works good with URLRequest and URLSession.shared.dataTask.
I can login to my app but when I try a GET request my server has no log that the request reached him. Finally I get the timeout error. Important, I am using https. I also tried to use http for GET Requests. on my NGINX Server I set TLS to 1.2 only (I am not a system specialist, I did that in the nginx cfg file.
Error Domain=NSURLErrorDomain Code=-1001 "Zeitüberschreitung bei der Anforderung." UserInfo={NSUnderlyingError=0x60400005abe0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=https://myurl, NSErrorFailingURLKey=https://myurl, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=Zeitüberschreitung bei der Anforderung.}
I am sure that my code for the URLRequest and URLSession is correct because against localhost and our development environment I do not have any of those problems.
Thats my code to create my URLRequest
private func buildUrlRequest(jsonObject:[String: Any], connectionType:ConnectionTypes, url:String) -> NSMutableURLRequest? {
let jsonDataSerialized:Data
do {
jsonDataSerialized = try JSONSerialization.data(withJSONObject: jsonObject)
} catch {
return nil
}
var request:NSMutableURLRequest
if nextData {
request = URLRequest(url: URL(string: self.nextRequestPage)!) as! NSMutableURLRequest
} else {
let tString = self.mBaseUrl + url
if let encoded = tString.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed),
var finalurl = URL(string: encoded)
{
if connectionType == .GET {
var tString:String
tString=finalurl.absoluteString
tString = tString.replacingOccurrences(of: "https", with: "http")
finalurl = URL(string:tString)!
}
request = URLRequest(url: finalurl) as! NSMutableURLRequest
} else {
return nil
}
}
request.httpMethod = connectionType.rawValue // i am using enum here
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("no-cache)", forHTTPHeaderField: "Cache-Control")
request.httpBody = jsonDataSerialized
if mUser != nil && mUser.getSessionId() != nil {
request.addValue("Token " + mUser.getSessionId()!, forHTTPHeaderField: "Authorization")
}
request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
request.timeoutInterval = 30.0
return request
}
This is how I create the task... after the method body I am using task.resume()
let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in .... (and so on)
I spend more than hours to solve this problem... But I have no idea.
I am not sure if the Problem is the Server Config or the Swift code...
The major problem was jsonObject:[String: Any] !
I changed it to jsonObject:[String: Any]?
In my code I've created the body for each request no matter if it was a POST GET PUT or what ever. Without the http-body in a GET request I have no problem anymore, no timeout! I correctly receive the data as expected.
I've also found out that it is not necessary to set the nginx's or lets encrypt sll_protocols to TLS 1.2 only in my case.
I hope if someone else runs into this issue, they will find this post :)

Posting to a secure API with swift

I'm trying to post to an API secured with a key (MailGun) with swift but it appears that my key is never utilized as I receive a Forbidden 401 error (Unauthorized - No valid API key provided) according to https://documentation.mailgun.com/api-intro.html#errors
I've verified the URL and key are correct by posting using curl, but I am unable to figure out why my key is not used here. I'm hoping someone can point in the right direction as to why this isn't authenticating correctly
My code is as such but I have replaced all the personal info with <>:
// Email the FBO with desired information
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: "https://api.mailgun.net/v3/<My Domain>/messages")!)
request.HTTPMethod = "POST"
let data = "from: Excited User <scheduler#<mg.mydomain.com>>&to: [bar#example.com,<my email>]&subject:Hello&text:Testinggsome Mailgun awesomness!"
request.HTTPBody = data.dataUsingEncoding(NSASCIIStringEncoding)
request.setValue("key-<my key>", forHTTPHeaderField: "api")
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
Update:
Banged away at it for a few hours and I still can't get my head around it. Maybe I'm not exactly sure what you mean? I can successfully get a response with curl by using:
curl -s --user 'api:key-<my personal key>' https://api.mailgun.net/v3/mg.<my domain>.com/messages -F from='Reservation Scheduler <scheduler#mg.<my domain>.com>' -F to=reservations#<my domain>.com -F subject='Curl Test' -F text='Test from terminal'
I tried inputting it explicitly like so:
request.setValue("api", forHTTPHeaderField: "username")
request.setValue("key-<my key>", forHTTPHeaderField: "password")
It looks to me like the basic auth credentials are never sent? How can I be sure that the fields are "user" and "password"?
After verifying my header appeared to be missing the authentication section of the header I was able to get this working properly with a large HTTP response. I put the full path into Keys.plist so that I can upload my code to github and broke out some of the arguments into variables so I can have them programmatically set later down the road.
// Email the FBO with desired information
// Parse our Keys.plist so we can use our path
var keys: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("Keys", ofType: "plist") {
keys = NSDictionary(contentsOfFile: path)
}
if let dict = keys {
// variablize our https path with API key, recipient and message text
let mailgunAPIPath = dict["mailgunAPIPath"] as? String
let emailRecipient = "bar#foo.com"
let emailMessage = "Testing%20email%20sender%20variables"
// Create a session and fill it with our request
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: mailgunAPIPath! + "from=FBOGo%20Reservation%20%3Cscheduler#<my domain>.com%3E&to=reservations#<my domain>.com&to=\(emailRecipient)&subject=A%20New%20Reservation%21&text=\(emailMessage)")!)
// POST and report back with any errors and response codes
request.HTTPMethod = "POST"
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
The Mailgun Path is in Keys.plist as a string called mailgunAPIPath with the value:
https://API:key-<my key>#api.mailgun.net/v3/<my domain>.com/messages?
Hope this offers a solution to anyone else having issues with MailGun and wanting to avoid a 3rd party solution!

Making HTTP Request with header in Swift

I am trying to make an HTTP request to the Imgur API. I am trying to retrieve all images associated with the tag "cats." The url, according to the Imgur API is: https://api.imgur.com/3/gallery/t/cats
the Imgur API states the following about the authorization needed to make get requests:
For public read-only and anonymous resources, such as getting image
info, looking up user comments, etc. all you need to do is send an
authorization header with your client_id in your requests. This also
works if you'd like to upload images anonymously (without the image
being tied to an account), or if you'd like to create an anonymous
album. This lets us know which application is accessing the API.
Authorization: Client-ID YOUR_CLIENT_ID
I've looked at the following questions and tried things suggested there, but none of them have helped.
JSON NSURLRequest with credentials
Swift GET request with parameters
How to make a Http get and set httpHeader in Swift?
My current code is this:
let string = "https://api.imgur.com/3/gallery/t/cats"
let url = NSURL(string: string)
let request = NSMutableURLRequest(URL: url!)
request.setValue("clientIDhere", forHTTPHeaderField: "Authorization")
//request.addValue("clientIDhere", forHTTPHeaderField: "Authorization")
request.HTTPMethod = "GET"
let session = NSURLSession.sharedSession()
let tache = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if let antwort = response as? NSHTTPURLResponse {
let code = antwort.statusCode
print(code)
}
}
tache.resume()
But I continually get a status code of 403, meaning authorization is required. What am I doing wrong?
I think you need to prepend Client-ID string to your actual client ID as for the header value:
request.setValue("Client-ID <your_client_id>", forHTTPHeaderField: "Authorization")
Updated for swift 4 :
func fetchPhotoRequest(YOUR_CLIENT_ID: String) {
let string = "https://photoslibrary.googleapis.com/v1/albums"
let url = NSURL(string: string)
let request = NSMutableURLRequest(url: url! as URL)
request.setValue(YOUR_CLIENT_ID, forHTTPHeaderField: "Authorization") //**
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let mData = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let res = response as? HTTPURLResponse {
print("res: \(String(describing: res))")
print("Response: \(String(describing: response))")
}else{
print("Error: \(String(describing: error))")
}
}
mData.resume()
}

NSURLRequest produce different result than HTTP proxy client

I send the same HTTP message from a HTTP proxy client and with NSURLRequest + NSURLConnection, and get back different result. It is an authentication request. From HTTP proxy authentication request is accepted, sending from app not. Why? Accepted means after redirection HTML will contains no Oops substring.
let url = NSURL(string: "http://www.swisshttp.weact.ch/en/user/login")
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let email2 = (viewController!.email.text as NSString).stringByReplacingOccurrencesOfString("#", withString: "%40")
let str = "name=\(email2)&pass=\(viewController!.password.text)&form_id=user_login" as NSString
let d = str.dataUsingEncoding(NSUTF8StringEncoding)
if let d2 = d {
request.HTTPBody = d2
let urlConnection = NSURLConnection(request: request, delegate: self)
}
UPDATE
I have put #teamnorge's code below into playground and into an empty Single View Application project. Returned HTML in project contains the Oops substring, code used in playground not containes it, any idea what is going on, why same request produce different HTML result? I get failed message also from iOS device and from simulator too.
UPDATE
Removed NSURLRequest cache like here recommended, but still not works as expected. And here.
UPDATE
Tried to remove all the credentials like here, but didn't help, no credential was found.
It looks like when you receive HTTP 302 and new Location URL, iOS does automatically fetch the page by this URL, so I guess your response is in fact the HTML content of the redirection page. Please verify.
UPDATE:
import UIKit
import XCPlayground
let url = NSURL(string: "http://www.swisshttp.weact.ch/en/user/login")
let request = NSMutableURLRequest(URL: url!)
let str = "name=kukodajanos%40icloud.com&pass=jelszo&form_id=user_login" as NSString
let d = str.dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPBody = d
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.currentQueue()) { response, maybeData, error in
if let data = maybeData {
let contents = NSString(data:data, encoding:NSUTF8StringEncoding)
println(contents)
if contents!.rangeOfString("Oops").length == 0 {
println("success")
} else {
println("failed")
}
} else {
println(error.localizedDescription)
}
}
XCPSetExecutionShouldContinueIndefinitely()

Resources