back4App, query using alamofire - mysql

I'm trying to make a query request on my database in back4app using Alamofire.
(i don't want to use Parse, for study purpose).
My DB has 2 simple field , Name and Age
I would like to send .get request using AF to obtain the data relative to a specific name.
I'm able to retrive all data in the DB with the following function:
func readData(){
AF.request(url!, method: .get, headers: headers).responseJSON { json in
print(json)
}
}
as per the back4app documentation in order to query a specific field is reported:
" specified the Parameters where URL parameter constraining the value for keys. It should be encoded JSON"
here my test:
func readDataQuery(name: String){
let param: [String: String] = [
"Name": name
]
AF.request(url!, method: .get, parameters: param, headers: headers)
.responseJSON { json in
print(json)
}
}
but it return an error:
success({
code = 102;
error = "Invalid parameter for query: Name";
})
how can I write the parameters to pass at the request?
thanks

You are getting this error because there is no such query parameter called "Name". In order to get objects via a condition, you would have to use the "where" clause like this.
let param: [String: String] = ["where": "{"Name":"Meimi"}"]
For more information please visit this website
https://docs.parseplatform.org/rest/guide/#query-constraints

Related

Could not cast value of type '__NSDictionaryI'

I m using this code to call my rest web service.
But if I try to decode the result of web service call I received error.
class func callPostServiceReturnJson(apiUrl urlString: String, parameters params : [String: AnyObject]?, parentViewController parentVC: UIViewController, successBlock success : #escaping ( _ responseData : AnyObject, _ message: String) -> Void, failureBlock failure: #escaping (_ error: Error) -> Void) {
if Utility.checkNetworkConnectivityWithDisplayAlert(isShowAlert: true) {
var strMainUrl:String! = urlString + "?"
for dicd in params! {
strMainUrl.append("\(dicd.key)=\(dicd.value)&")
}
print("Print Rest API : \(strMainUrl ?? "")")
let manager = Alamofire.SessionManager.default
manager.session.configuration.timeoutIntervalForRequest = 120
manager.request(urlString, method: .get, parameters: params)
.responseJSON {
response in
switch (response.result) {
case .success:
do{
let users = try JSONDecoder().decode(OrderStore.self, from: response.result.value! as! Data)
}catch{
print("errore durante la decodifica dei dati: \(error)")
}
if((response.result.value) != nil) {
success(response as AnyObject, "Successfull")
}
break
case .failure(let error):
print(error)
if error._code == NSURLErrorTimedOut {
//HANDLE TIMEOUT HERE
print(error.localizedDescription)
failure(error)
} else {
print("\n\nAuth request failed with error:\n \(error)")
failure(error)
}
break
}
}
} else {
parentVC.hideProgressBar();
Utility.showAlertMessage(withTitle: EMPTY_STRING, message: NETWORK_ERROR_MSG, delegate: nil, parentViewController: parentVC)
}
}
This is the error that I can print:
Could not cast value of type '__NSDictionaryI' (0x7fff86d70b80) to 'NSData' (0x7fff86d711e8).
2021-09-27 16:34:49.810245+0200 ArrivaArrivaStore[15017:380373] Could not cast value of type '__NSDictionaryI' (0x7fff86d70b80) to 'NSData' (0x7fff86d711e8).
Could not cast value of type '__NSDictionaryI' (0x7fff86d70b80) to 'NSData' (0x7fff86d711e8).
CoreSimulator 732.18.6 - Device: iPhone 8 (6F09ED5B-8607-4E47-8E2E-A89243B9BA90) - Runtime: iOS 14.4 (18D46) - DeviceType: iPhone 8
I generated OrderStore.swift class from https://app.quicktype.io/
//EDIT
.responseJSON returns deserialized JSON, in this case a Dictionary. It cannot be cast to Data what the error clearly confirms.
To get the raw data you have to specify .responseData
Replace
.responseJSON {
response in
switch (response.result) {
case .success:
do {
let users = try JSONDecoder().decode(OrderStore.self, from: response.result.value! as! Data)
with
.responseData {
response in
switch response.result {
case .success(let data):
do {
let users = try JSONDecoder().decode(OrderStore.self, from: data)
Consider that AF 5 supports even .responseDecodable to decode directly into the model
.responseDecodable {
(response : DataResponse<OrderStore,AFError>) in
switch response.result {
case .success(let users): print(users)
Side notes:
As mentioned in your previous question there is no AnyObject in the AF API. The parameters are [String:Any] and responseData is the decoded type. I recommend to make the function generic and use the convenient Result type.
Delete the break statements. This is Swift.
This is an addendum to Vadian's answer. I'm trying to illustrate the process that lead you into this error, with the hopes that you can notice it in the future, before it leads you astray
This is a pretty common "pattern" of error.
Picture it as though you're traversing a maze, starting from some initial data format, and trying to get to some destination data format. At each point along the way, there are several options to choose from, some which get you closer to your goal, and some which lead you further away.
You've chosen to enter the maze at the entryway called responseJSON, whose callback will give you a AFDownloadResponse<Any> (which is the inferred type of the variable you called response).
JSON structures always have an array or dictionary at the top level. Since Alamofire can't statically know which kind of JSON you'll be dealing with, it models this with an Any. At runtime, the type of the Value will be either NSDictionary (or one of its concrete subclasses, like __NSDictionaryI) or NSArray (or one of its concrete subclasses).
You then decide to get the result of that response. Its static type is Result<Any, Error>. You switch over this error, ensuring you're dealing with the success case and not the failure case. Inexplicably, you ignore the payload value associated with the success, but later force unwrap it out with result.response.value!.
result.response.value is an Any, but to placate the compiler your force-cast it to a Data. But we already know this will only ever be an NSArray or NSDictionary, so this will never work.
You could keep wandering around in this area of the maze, and stumble to the end goal via a long path. For example, you could force cast to NSDictionary, then re-serialize that dictionary structure back to a JSON string, which you can turn into Data, only for you to then pass it to JSONDecoder().decode, which will then decode that JSON back. Of course, this is all awfully round-about and wasteful. The issue was the that responseJSON maze entrance was not the right one for where you're trying to go!
You could have instead entered into the responseData maze entrance, which gets you right to your Data destination!
Though you might then realize that the Data was a red herring all along. You didn't actually want Data. You wanted to decode an OrderStore, and Data was how you thought you needed to get there. But it turns out that so many people were entering through the Data entrance with the intent to decode some JSON, that the Alamofire people carved out a new entrance just for you: responseDecodable. It takes you right to the OrderStore, and fiddles around with the JSON, Data or whatever, under the hood where you don't have to worry about it.

Alamofire string parameter hardcoded works but passing as string parameter does not

I'm attempting to make a Alamofire service call to retrieve a list of items in JSON. The issue I am having is that anytime I type in a special character: such as ' it somewhere resolves the string a unicode string while sending the request. When I type in o'sheas its coming back that I'm searching O\U2019sheas
func sendGetRequest(passedInString: String) {
PARAMETERS["searchTxt"] = passedInString
Alamofire.request(URL, method: .get , parameters: PARAMETERS, headers: HEADER)
.validate(statusCode: 200..<400)
.responseJSON { response in
debugPrint(response.request!)
switch response.result {
// GETTING NO RESULTS BECAUSE THE REQUEST IS TURNING the o'sheas into O\U2019sheas
But the odd thing is, if I just replace this:
PARAMETERS["searchTxt"] = passedInString
with a hardcoded string (the one I'm typing initially and getting no results)
PARAMETERS["searchTxt"] = "o'sheas"
...it works just fine and does not convert this to O\U2019sheas. Any idea how to fix this, and more importantly, why this is happening when passed in as a String parameter as opposed to hard coded string?
UPDATE:
I've tried adding the URLEncoding.default as the encoding parameter, same results.
I've also tried creating a Swift String Extension to be used on the searchTxt as passing it as parameter like so:
PARAMETERS["searchTxt"] = passedInString.escapeSpecialCharacters()
extension String {
mutating func escapeSpecialCharacters() {
// 1. Define replacements
let replacementCharacters = ["'" : "\'"]
// 2. Cycle through each replacement defined in the replacementCharacters array and remodify the string accordingly.
replacementCharacters.keys.forEach {
// 3. Replacing self with new modified string
self = self.replacingOccurrences(of: $0, with: replacementCharacters[$0]!)
}
}
}
But same results.
If you are sure about this Unicode problem, then you can use Encoder and Decoder functionality to handle this.
Or if you know the your String always will be same, then use Regex expression to append '\'
I think the problem is with the "get" - cause it will use your string in the URL as parameter, the "'" can't be handelt so well.
Try to create a url with URLComponents
var urlComponents = URLComponents()
urlComponents.scheme = scheme
urlComponents.host = host
urlComponents.path = path
urlComponents.queryItems = [queryItem]
then use urlComponents.url in
Alamofire.request(urlComponents.url, method: .get, headers: HEADERS) {...}
URLQueryItem(name: "Param", value: "eter")
Try below lines of code. May help you.
originalString = "o'sheas"
var escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
PARAMETERS["searchTxt"] = escapedString

Send empty array with Alamofire API Rest

I want to send an empty array to a Rest Full API by using patch method. But i don't know why it is not working. In fact, i am also using postman for testing my requests, and this request works fine in postman ( I want wordTrads be empty ) :
And this is how i've implemented that API called in Swift by using Alamofire :
let parameters = [
"wordTrads" : [],
]
Alamofire.request("\(Auth.URL_API)/lists/205",method: .patch, parameters : parameters).responseJSON { (response) in
print("List patched")
}
But in swift it's not working like if Alamofire doesn't send empty arrays.
I am using Alamofire 4.6.0 and Swift 4.
Your screen snapshots suggest you're expecting to send JSON, but your Alamofire syntax is not doing that. You need to add encoding of JSONEncoding.default if you want to send JSON:
let parameters = [
"wordTrads" : []
]
Alamofire.request("\(Auth.URL_API)/lists/205", method: .patch, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON { response in
switch response.result {
case .success(let value): print(value)
case .failure(let error): print(error)
}
}
And if you do that, the body of the request includes that empty array in JSON form:
{"wordTrads":[]}

How to detect when Alamofire request is null?

I am using Alamofire to do my requests of my API on my Swift application and it works well but I also want to detect when the JSON response is equals to null.
I have tried comparing the response to nil and NSNull but none of those worked for me. I also have tried using JSON.empty but it also does not seem to work. Further, I have created a default option on my switch application trying to catch the options that are not success or failure.
Actually I have only maintained the JSON.empty option but it never enters on else statement.
This is the code that I have right now:
Alamofire.request(encodedUrl!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in
switch(response.result) {
case .success(_):
if let JSON = response.result.value as? [[String : AnyObject]]{
if JSON.isEmpty == false{
//Here the code if the request returns data
}else{
//Here I wanted to use the code if null is retrieved
}
}else{
//The JSON cannot be converted
}
break
case .failure(_):
//Failure
break
}
}
How can I handle null responses on Alamofire?
Thanks in advance!
According to you code, it'll hit the // The JSON cannot be converted since null can't be casted to [[String: AnyObject]].

Alamofire unexpectedly found nil while unwrapping an Optional, yet I can see the JSON

Using AlamoFire I can make an API call to my endpoint, it works and connects as expected. Using the print tools I can print the JSON response to the console and see the JSON string, but I am unable to get this string to move to the next function.
I keep getting the error:
"fatal error: unexpectedly found nil while unwrapping an Optional value (lldb)"
My code looks like this:
func getDataForUser(Username:String, UserToken:String) {
print("Getting data for user \(Username)")
Alamofire.request(.POST, baseURL+userdataURL, parameters: ["Username": Username, "UserToken": UserToken]).response { (req, res, data, error) -> Void in
let jSONResponse: NSDictionary = (try! NSJSONSerialization.JSONObjectWithData(data!,options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary
print(jSONResponse)
if(jSONResponse["Success"] as! Bool == true) {
print("Success! API Request Worked")
self.delegate!.didReceiveAPIResults(jSONResponse)
}
}
}
The error is on line:
self.delegate!.didReceiveAPIResults(jSONResponse)
The console looks like this:
jSONResponse NSDictionary 2 key/value pairs 0x78e8d6a0
[0] (null) "Success" : "1"
[1] (null) "Response" : 2 key/value pairs
The debug screen for jSONResponse gives me data that I can drill into so I know its not nil.
Where is the nil coming from and how do I resolve?
In Swift, "1" is not equal to a Bool value of true.
It's crashing at jSONResponse["Success"] as! Bool == true. You could change this to jSONResponse["Success"] as! String == "1".
If you are able to modify the source of the API you're consuming, you're probably better of making Success a true/false JSON bool value, and leaving your Swift code as is.
My initial thoughts were that the JSON handler or API Controller were wrong.
What I had not passed was the delegate variable in the view controller setup.
EG:
api.delegate = self
Thank you to #paulvs and Eric D for pointing that out.