How to change error.localizedDescription to JSON by Swift? - 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"] ?? ""

Related

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

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.

Issue while displaying correctly an error message for Invalid credentials

I would like to display the content of the error received from my server in my iPad apps using Swift, but I can not display it correctly:
(lldb) po (response.rawString)
"{\"message\":\"Invalid Credentials\"}"
I would like to display only :
Invalid Credentials
You could add a custom type for your error and make it conform to Codable
struct ServerError: Error, Codable {
let message: String
}
and then decode value of response.rawString using JSONDecoder
let decoder = JSONDecoder()
guard
let data = response.rawString.data(using: .utf8),
let error = try? decoder.decode(ServerError.self, from: data)
else {
return
}
print(error.message) // output: Invalid Credentials

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['']

Get error description from caught error

I do something like this:
let decoder = JSONDecoder()
do
{
let decodedData = try decoder.decode(type, from: data)
}
catch DecodingError.dataCorrupted
{
let descr = ???
Log.error("Failed to decode JSON response. Error was: \(descr)")
}
how can I access the error description from this? Why can I not simply catch any kind of error in one catch and access its debug description?
How to access the error description
In Swift, a lot of the errors conform to the protocol LocalizedError, which will give you a variable localizedDescription: String? that you can use to print an error message. DecodingError should not be any different.
How to catch any kind of error
You should be able to catch any kind of errors in one catch. In order to do this, you can use
catch let error as DecodingError {
// Any error of type DecodingError
}
or
catch {
// Any possible error
}
Putting it all together
If I understand correctly, you are tring to catch any error of type DecodingError. In that case, you can simply do the following
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(type, from: data)
} catch let error as? DecodingError {
Log.error("Failed to decode JSON response. Error was: \(String(describing: error.localizedDescription))")
}