How to get data from call cloud functions using swift app? - swift

Now I'm developing cloud functions.
Please teach me how to get data from call cloud functions using swift app.
I use TypeScript in cloud functions as backend service.
import * as functions from "firebase-functions"
import * as admin from "firebase-admin"
admin.initializeApp(functions.config().firebase)
export const helloWorld = functions
.https.onCall((data: any, context: any) => {
functions.logger.info("Hello logs!", { structuredData: true })
return { result: "Hello World" }
})
And in frontend I use swift.
func callCloudfunction(){
functions.httpsCallable("helloWorld").call(["name": "taro"]) { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
print(message)
}
}
if let data = (result?.data as? [String: Any]), let text = data["result"] as? String {
print("SUCCESS: \(text)")
}
}
}
In Swift I think functions.httpsCallable("helloWorld").call(["name": "taro"]) method is like http post request. So in TypeScript I can get the name's data using data argument.
But I don't know how to get result data from TypeScript. In TypeScript I created json { result: "Hello World" }.
How do I fix the process in swift? I think this code below is not good.
if let data = (result?.data as? [String: Any]), let text = data["result"] as? String {
print("SUCCESS: \(text)")
}
And please tell me how to handle error process.
Some class and property in error handling are already deprecated .FunctionsErrorDomain and FunctionsErrorDetailsKey.
Please teach me how to handle getting data and handle error process.
Thank you.

Related

How to change error.localizedDescription to JSON by Swift?

In Swift I got the error from Cloud Functions.
And I caught the error like this
functions.httpsCallable("addMessage").call(["text": inputField.text]) { result, error in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
}
}
}
The message get like JSON format from Cloud functions.
{"message":"text is required","status":"INVALID_ARGUMENT"}
If I got the error message from Cloud functions, and I want to display to the user.
First I tried
let status = message["status"]
But I got No exact matches in call to subscript in xcode.
How do I resolve this problem?
error.localizedDescription is obviously a JSON string, you have to deserialize it
let messageJSON = error.localizedDescription
let messageDictionary = try? JSONDecoder().decode([String:String].self, from: Data(messageJSON.utf8))
let message = messageDictionary?["message"] ?? ""

How to make functions.httpsCallable("findItems").call(["lat": userLocation?.latitude, "long": userLocation?.longitude]) request?

There is not enough documents about firebase functions.httpsCallable("findItems").call() usage. I have deployed functions on firebase:
exports.findItems = functions.https.onCall((data, context) => {
// Grab the long parameter.
functions.logger.log(data.long, typeof data.long);
functions.logger.log(data.lat, typeof data.lat);
const long = parseFloat(data.long);
const lat = parseFloat(data.lat);
functions.logger.log(long, typeof long);
functions.logger.log(lat, typeof lat);
//...
}
I make a request in swift using functions.httpsCallable("findItems").call() but the log always says there is no correct parameters:
functions.httpsCallable("findItems").call(["lat": userLocation?.latitude, "long": userLocation?.longitude]) { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
}
// ...
print(error)
return
}
print(result?.data)
do{
let json = try JSONDecoder().decode([ItemLocation].self, from:result?.data as! Data)
print(json)
}catch{
}
// if let text = (result?.data as? [String: Any])?
//(result?.data as? [String: Any])?["text"] as? String {
//self.resultField.text = text
}
You can find the offcial documents from : https://firebase.google.com/docs/functions/callable
-----Update---------
I have tried everything by debugging and the passed parameters are always undefined but I follow every step on the official doc.
I have made changes and use onCall but it still doesn't work?
You are mixing up HTTP functions with callable functions. Your client code is trying to call a callable function, but your function itself is defined as an HTTP function. This won't work at all. You should review the documentation for callable function and use functions.https.onCall instead of functions.https.onRequest to define your function. They are completely different APIs.

Alamofire, Swift: What could be causing this error?

What could be causing this error?
All of a sudden out of nowhere I started getting the error below. I have reinstalled the cocoapod, cleaned the build folder, and reinstalled the app already and none of that has fixed the error.
ERROR: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
CODE:
let recoverUrl = "http://www.website.com/recover.php?email=\(emailData)&local=application"
let urlEncodedString = recoverUrl.replacingOccurrences(of: " ", with: "%20")
parseRecover(url: urlEncodedString)
//////////////
func parseRecover(url : String){ AF.request(url).responseJSON(completionHandler: { response in self.parseData(JSONData: response.data!) }) }
func parseData(JSONData : Data){
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONObject
if let recoverJSON = readableJSON["Recover"] as? [JSONObject] {
for i in 0..<recoverJSON.count {
let JSON = recoverJSON[i]
let status = JSON["status"] as! String
let message = JSON["message"] as! String
if status == "Error" {self.Alert01("\(message)")}
else if status == "Success" { self.Alert02("\(message)") }
}}}
catch { print(error) }
}
ERROR IS OCCURING AT:
func parseRecover(url : String){ AF.request(url).responseJSON(completionHandler: { response in self.parseData(JSONData: response.data!) }) }
There's no guarantee that a response has data, so force unwrapping the value can lead to crashes. I suggest you create Decodable types to parse your responses and use Alamofire's responseDecodable method to handle your responses.
Additionally, even if you don't adopt Decodable, responseJSON already parses your response Data using JSONSerialization, so you can just access the response.result to see the output.
SOLVED: The issue was within my php file. I was using $_GET[''] and it should have been a $_POST[''] or $_REQUEST['']

What does " Value of tuple type '(String, JSON)' has no member 'subscript' " refer to in Xcode?

So for my file I am trying to use Alamofire to make a request in order to get Photos from Flickr using their API.
I am using CoreData, Alamofire, and SwiftyJSON
The method is as follow:
func getImagesFromFlickr(_ selectedPin: Pin, _ page: Int, _ completionHandler: #escaping (_ result: [Photo]?, _ error: NSError?) -> Void) {
/* Set Parameters */
let methodParameters: [String:String] = [
Constants.FlickrParameterKeys.Method: Constants.FlickrParameterValues.SearchMethod,
Constants.FlickrParameterKeys.APIKey: Constants.FlickrParameterValues.APIKey,
Constants.FlickrParameterKeys.BoundingBox: bboxString(longitude:selectedPin.longitude , latitude: selectedPin.latitude),
Constants.FlickrParameterKeys.Latitude: "\(selectedPin.latitude)",
Constants.FlickrParameterKeys.Longitude: "\(selectedPin.longitude)",
Constants.FlickrParameterKeys.PerPage: "21",
Constants.FlickrParameterKeys.Page: "\(page)",
Constants.FlickrParameterKeys.SafeSearch: Constants.FlickrParameterValues.UseSafeSearch,
Constants.FlickrParameterKeys.Extras: Constants.FlickrParameterValues.MediumURL,
Constants.FlickrParameterKeys.Format: Constants.FlickrParameterValues.ResponseFormat,
Constants.FlickrParameterKeys.NoJSONCallback: Constants.FlickrParameterValues.DisableJSONCallback
]
/* Build the URL */
let url = flickrURLFromParameters(methodParameters)
/* Make the request with Alamofire */
Alamofire.request(url).validate(statusCode: 200..<300).responseJSON { (response) in
if response.result.isSuccess {
print("Success! Got the Images from Flickr!")
let flickrJSON : JSON = JSON(response.result.value!)
print(flickrJSON)
let photosDict = flickrJSON["photos"]
let photoArray = photosDict["photo"]
performUIUpdatesOnMain {
let context = CoreDataStack.getContext()
var imageUrlString = [Photo]()
for url in photoArray {
let urlString = String(url[Constants.FlickrResponseKeys.MediumURL])
let photo : Photo = NSEntityDescription.insertNewObject(forEntityName: "Photo", into: context ) as! Photo
photo.urlString = urlString
photo.pin = selectedPin
imageUrlString.append(photo)
CoreDataStack.saveContext()
}
completionHandler(imageUrlString, nil)
}
} else {
print("Error: \(String(describing: response.result.error))")
}
}
}
The error is within this line of code:
let urlString = String(url[Constants.FlickrResponseKeys.MediumURL])
I get this error in Xcode saying " Value of tuple type '(String, JSON)' has no member 'subscript' "
Any help with why I am getting this error is much appreciated.
Also, any recommendations on how I can implement this method better is much appreciated.
If you would like to take a look at my project it is under the branch called "Networking-with-Alamofire"
The link is here:
https://github.com/RobertoEfrainHernandez/Virtual-Tourist-Udacity/tree/Networking-with-Alamofire
If you look under the master branch I did my networking code using URLSessions and my goal for the Networking-with-Alamofire branch was to convert those networking methods using Alamofire and SwiftyJSON.
for url in photoArray
I suppose here url not always a dictionary, in your case you get a tuple (value1, value2) and obviously you cannot access parameters in tuple via subscript syntax.
You need to check JSON response and make some adjustments in mapping func

What am I doing wrong downloading data from parse?

I am trying to download some data from parse but I get an error message saying "Value of type 'PFObject' has no member 'name' What am I doing wrong?
here is my parse dashboard screenshot
here is my code to upload the data to parse:
var coordinates = PFGeoPoint (latitude: (newCoordinate2.latitude), longitude:(newCoordinate2.longitude))
var aboutSpot = PFObject(className: "spotdetail")
aboutSpot ["PFGeoPoint"] = coordinates
aboutSpot["name"] = "name"
aboutSpot.saveInBackgroundWithBlock { (succes, error) -> Void in
print("separate name and geopoint have been saved")
}
and here is my code to download my data:
var query = PFObject.query()
query!.findObjectsInBackgroundWithBlock ({ (objects, error) in
if let places1 = objects {
for object in places1 {
if let spotdetail = object as? PFObject {
self.rideSpots.append(spotdetail.name!)
}
}
}
print(self.rideSpots)
})
also not that on the line that says
if let spotdetail = object as? PFObject {
I get a warning saying "conditional cast from 'PFObject' to 'PFObject' always succeeds
I can probably solve this pretty easily but I wanted to mention it in case it could help solve the issue