Calling Cloud Function from Swift with JSON data - swift

I have a Cloud Function hosted on Firebase that I am trying to call from a Swift app. It works fine when I call it from command line with the following script, however there is some issue with parsing the JSON data when I call it from swift.
Command Line (works perfectly)
time curl -v -X POST -d '{"url":"https://cdn.bmstores.co.uk/images/hpcProductImage/imgFull/303441-Volvic-6x500ml-Naural-Mineral-Water1.jpg"}' -H "Content-type: application/json" https://us-central1-themagicfactory-5cf7a.cloudfunctions.net/fastMatches
Swift Code (doesn't work)
functions.httpsCallable("fastMatches").call("{\"url\":\"https://cdn.bmstores.co.uk/images/hpcProductImage/imgFull/303441-Volvic-6x500ml-Naural-Mineral-Water1.jpg\"}", completion: {(result,error) in
if let error = error{
print("An error occurred while calling the test function: \(error)" )
}
print("Results from test cloud function: \(result)")
})
Python Pseudo (cloud function)
def fastMatches(request):
print(request)
req = urllib.request.urlopen(request.json["url"])
Request being weird when called from Swift
EDIT: I get the same weird results even if I call it from a manual HTTPs request.
let json: [String: String] = ["url": "https://cdn.bmstores.co.uk/images/hpcProductImage/imgFull/303441-Volvic-6x500ml-Naural-Mineral-Water1.jpg"]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// create post request
let url = URL(string: "https://us-central1-themagicfactory-5cf7a.cloudfunctions.net/fastMatches")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
print(data,response,error)
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
}
task.resume()

Related

error: missing argument for parameter 'from' in call

I am trying to make an http get request and I want to go back to convert the data obtained in JSON to an Array and send it as a parameter to a leaf template from the routes.swift file, all this using Vapor framework but I get the following error:
Error: missing argument for parameter 'from' in call
let json = JSONDecoder().decode(Todos.self).
Here is my code:
app.get("datos") {req -> EventLoopFuture<View> in
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")
guard let requestUrl = url else { fatalError("Error url") }
var request = URLRequest(url: requestUrl)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print("Error took place \(error.localizedDescription)")
return
}
if let response = response as? HTTPURLResponse {
print("Response HTTP Status code: \(response.statusCode)")
}
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
}
}
task.resume()
let json = JSONDecoder().decode(Todos.self)
return req.view.render("objetos", json)
}
struct Todos: Codable{
var userId: Int
var id: Int
var title: String
var body: String
}
Don't use URLSession - it doesn't integrate nicely with Vapor's futures and Vapor's client built on top of AsyncHTTPClient is much more performant and integrated. You can then rewrite your code to look like:
app.get("datos") { req -> EventLoopFuture<View> in
req.client.get("https://jsonplaceholder.typicode.com/posts").flatMap { response in
let todos = try response.content.decode(Todos.self)
return req.view.render("objetos", json)
}
}

API post method using urlsession showing error in swift

I have the parameters which has to be saved to database using post method api.
The property_image_url is ["https://res.cloudinary.com/dtwvevtm7/image/upload/v1617203478/j8mqat97ssrctsnzpjlc.jpg","https://res.cloudinary.com/dtwvevtm7/image/upload/v1617203479/j1rhedrsnrud7fkva1bl.jpg"]
The parameters are as follows:
["price": "dry", "listing_description": "Dghb", "listing_type": "Residential", "property_image_url": "[\"https://res.cloudinary.com/dtwvevtm7/image/upload/v1617203478/j8mqat97ssrctsnzpjlc.jpg\",\"https://res.cloudinary.com/dtwvevtm7/image/upload/v1617203479/j1rhedrsnrud7fkva1bl.jpg\"]", "address": "chennai ", "listing_use": "SubLease", "property_video_url": "", "title": "huffy"]
Here when the value is property_image_url,it is showing unnescessary white space and escape character.
The code used to post the data via API is given below:
let url = URL(string: url)! //change the url
//create the session object
let session = URLSession.shared
//now create the URLRequest object using the url object
var request = URLRequest(url: url)
request.httpMethod = "POST" //set http method as POST
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameter, options: .fragmentsAllowed) // pass dictionary to nsdata object and set it as request body
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.addValue(self.usertoken, forHTTPHeaderField: "x-token")
//create dataTask using the session object to send data to the server
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
print("data is",data)
guard error == nil else {
return
}
guard let data = data else {
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print("new listing json is",json)
DispatchQueue.main.async {
self.navigationController?.view.makeToast("Listing Updated successfully", duration: 3.0, position: .bottom)
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Home") as! Home
self.navigationController?.pushViewController(vc, animated: true)
}
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
}
This post method is throwing error saying
["errors": <__NSArrayM 0x283120810>(
Title Required,
Listing Type Required,
Listing Use Required
)
]
Here,in the parameter all these values are filled but still it is showing like that these values are empty.
Let me know what is the issue in passing the parameter and calling the API.

Use CURL from API

I am new with APIs and I am trying to import data from the API of Schiphol Airport. First I tried this link in my query, but then I got the following result.
https://api.schiphol.nl/public-flights/flights?app_id=////APPID////&app_key=////APPKEY////&includedelays=false&page=0&sort=%2Bscheduletime
result: {code = 406; description = "Can't retrieve version number from accept-header";}
I think that I have to use the CURL to get a result, but I don't know how to do that in SWIFT 3.
CURL: curl -X GET --header "Accept: application/json" --header "ResourceVersion: v3" "https://api.schiphol.nl/public-flights/flights?app_id=////APPID////&app_key=////APPKEY////&includedelays=false&page=0&sort=%2Bscheduletime"
My code now looks like this:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let url = NSURL(string: "https://api.schiphol.nl/public-flights/flights?app_id=////APPID////&app_key=////APPKEY////&scheduledate=2017-07-11&airline=CND&includelays=false&page=0&sort=%2Bscheduletime")!
let task = URLSession.shared.dataTask(with: url as URL) { (data, response, error) -> Void in
if let urlContent = data {
do{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers)
print(jsonResult)
} catch{
print("failed")
}
}
}
task.resume()
}
Can somebody help me out?
Instead of a simple URL use an URLRequest and add the header field.
This is the Swift equivalent of the cURL syntax:
let url = URL(string: "https://api.schiphol.nl/public-flights/flights?app_id=xxxxxxx&app_key=yyyyyyyyyyyyy5&scheduledate=2017-07-11&airline=CND&includelays=false&page=0&sort=%2Bscheduletime")!
var request = URLRequest(url: url)
request.addValue("v3", forHTTPHeaderField: "ResourceVersion")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) -> Void in ...
I made the personal data anonymous.
Note: Don't pass any options in JSONSerialization, the option .mutableContainers is completely useless in Swift.
let jsonResult = try JSONSerialization.jsonObject(with: urlContent)
According to the API documents you need to set the ResourceVersion in the headers for the call.
The following should work:
var req = URLRequest.init(url: URL.init(string: "https://api.schiphol.nl/public-flights/flights?app_id=//APPID//&app_key=//APPKEY//")!)
req.setValue("v3", forHTTPHeaderField: "ResourceVersion")
URLSession.shared.dataTask(with: req) { (data, response, error) in
print(try? JSONSerialization.jsonObject(with: data!, options: .init(rawValue: 4)))
}.resume()

shuttstock api image search in swift

https://developers.shutterstock.com/guides/search
This is the api docs for shutterstock.
I am doing a simple image search using the shutterstock image seach api get request.
I am able to output a JSON file using curl(as shown in the api docs),
But If i do a http request through swift(in code),
I get an error.
This is my code for the http request
func set_image(country:String) {
let client_id = "6e1f7771194a5a260e05"
let client_secret = "secretttt"
let base_url = "https://\(client_id):\(client_secret)#api.shutterstock.com/v2/images/search?query=\(country)"
let escapedStringURL:String = base_url.replacingOccurrences(of: " ", with: "%20")
let url = URL(string: escapedStringURL)
print(url)
URLSession.shared.dataTask(with: url!, completionHandler: {
(data, response, error) in
if(error != nil){
print("error in image search")
}else{
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
OperationQueue.main.addOperation({
// self.trip_tableview.reloadData()
print(json)
})
}catch let error as NSError{
print(error)
}
}
}).resume()
}
Is this because curl behaves differently?
If so, how do I run the http request using curl in swift?
EDIT
It's technically not an error I guess.
When I run my code it outputs (which is the same output I get when I just run the url in my browser),
{"message":"Authorization header required"}
But if i run the same url with curl I get the output that I want.

Get request return error code 405 - method not allowed

I've wrote a function for GET request from rest and it says that i have method not allowed - code 405 which is werid and i can not find solution for that.
I am doing GET via current token which was assigned to the user after logged in.
Could someone have a look on the code and tell me what might be wrong ?
func getRequest() -> Void {
let json: [String: Any] = ["token": SessionMenager.Instance.token]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// create post request
let url = URL(string: MY_URL)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
// insert json data to the request
request.httpBody = jsonData
request.setValue("application/json;charest=utf-8", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
if let httpResponse = response as? HTTPURLResponse {
print("GET : code - \(httpResponse.statusCode)")
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
} else{
print(error.debugDescription)
}
}
task.resume()
}
Thanks in advance!!