How to use this JSON response? - json

I want to use donation payment with my custom website.
There is a URL I should connect to and pass 2 value with the name "sku" & "device_id".
As asnwer the web gives me a value with name of "status" and a paycode with a value like this "726287618769179".
If "status" equals "READY_TOPAY" I should go to next url+paycode and
then user can fill card number and password and etc.
I use this code to connect and communicate with the web:
let DID = UIDevice.currentDevice().identifierForVendor!.UUIDString
print("Device ID is : \(DID)")
let url = NSURL (string: "https://qqqq.com/rest-api/pay-request");
let requestObj = NSURLRequest(URL: url!);
webView.loadRequest(requestObj);
let request = NSMutableURLRequest(URL: NSURL(string: "https://qqqq.com/rest-api/pay-request")!)
request.HTTPMethod = "POST"
let postString = "mypayid&device_id=\(DID)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
guard error == nil && data != nil else { // check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
if (responseString?.UTF8String.) {
print("YESsssss")
}
}
task.resume()
The problem is I get the first JSON answer like this:
responseString = Optional({"error":false,"status":"READY_TO_PAY","pay_code":"4443697552108","prd_status":1})
I don't know what to do with this!
How should I tell if "status" equals "READY_TO_PAY" go to next url+paycode?

Instead of making a String from your JSON data with NSString(data: data!, encoding: NSUTF8StringEncoding), decode the JSON data to a dictionary, and access its contents by safely subscripting:
if let json = try? NSJSONSerialization.JSONObjectWithData(data!, options: []) {
if let content = json as? [String:AnyObject],
status = content["status"] as? String,
payCode = content["pay_code"] as? String {
print(status)
print(payCode)
}
}
Now you can easily compare status with "READY_TO_PAY" and take necessary actions.

Related

Swift and JSON driving me crazy

I am really getting stuck on this.
I have created a JSON service, that returns data like this:
[
{
"docNameField": "Test",
"docNumField": 22832048,
"docVerField": 1,
"docDataBaseField": "Legal",
"docCheckedOutWhenField": "03/05/2020",
"whereCheckedOutField": "PC0X8J9RD"
}
]
This is Postman output.
No matter how I try, I cannot seem to be able to put together the correct combination og HTTP call, deserialization, types and so on to get a list of objects out in the end.
This func below outputs this:
JSON String: Optional("[{\"docNameField\":\"Test\",\"docNumField\":22832048,\"docVerField\":1,\"docDataBaseField\":\"Legal\",\"docCheckedOutWhenField\":\"03/05/2020\",\"whereCheckedOutField\":\"PC0X8J9RD\"}]")
func LoadLockedDocumentsByDocnum(docNum:Int32) {
let json: [String: Any] = ["action":"getCheckedOutDocuments","adminUserName":"\(APPuserName)","adminPassword":"\(APPuserPassword)","adminDomain":"\(APPuserDomain)","applicationKey":"19730905{testKey}","searchTerm":docNum]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
self.documentEntries.removeAll()
let url = URL(string: "https://{URL}//CheckOut")!
var request = URLRequest(url: url)
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") //Optional
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let session = URLSession.shared
let dataTask = session.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if let resultat = response as! HTTPURLResponse?{
if resultat.statusCode == 200{
if error != nil {
}
else {
print(data!)
if let nydata = data{
print("JSON String: \(String(data: data!, encoding: .utf8))")
}
}
}}
}
dataTask.resume()
}
You seem to have come pretty close. To get a list of objects out, you first need to declare that object:
struct MyResponseObject: Decodable { // please give this a better name
let docNameField: String
let docNumField: Int
let docVerField: Int
let docDataBaseField: String
let docCheckedOutWhenField: Date
let whereCheckedOutField: String
}
And then use a JSONDecoder to deserialise the JSON. Instead of:
print("JSON String: \(String(data: data!, encoding: .utf8))")
write:
let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"
decoder.dateDecodingStrategy = .formatted(formatter)
do {
// here's your list of objects!
let listOfObjects = try decoder.decode([MyResponseObject].self, from: data!)
} catch let error {
print(error) // an error occurred, you can do something about it here
}

How to POST data from multiple view controllers to server with JSON using SWIFT

I need help with combining data collected from firstVC, secondVC, and thirdVC and serializing those in the fourthVC.
This link helps with one VC but I have to send only ONE FILE of JSON DATA to the server.
How to create and send the json data to server using swift language
The other method is passing a dictionary array from firstVC, secondVC, and thirdVC to the fourthVC and from the fourthVC convert the dictionaries into JSON. But i don't know how to do that.
I used the format from the answer provided in the link above, but if you need additional info, I will gladly cooperate. Thanks!
PS. Please give me useful comments that will help in any way. I need the code and not feedbacks like doing my own research and such cause I have been stressing about this for nearly a month now.
This is the UserDefault keys
if let AC = UserDefaults.standard.value(forKey: "Acc") as? String {
labeltext.text = "\(AC)"
}
if let TY = UserDefaults.standard.value(forKey: "Taxyear") as? String {
taxtext.text = "\(TY)"
}
if let BB = UserDefaults.standard.value(forKey: "Bsb") as? String {
bsbtext.text = "\(BB)"
}
Here is my JSON code
#IBAction func save(_ sender: Any){
typealias JSONDictionary = [String:Any]
let parameters = ["BankAccountNumber": "Acc", "Tax Year": "Taxyear", "my-bsb": "Bsb"]
let url = URL(string: "https://server:port/")! //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
let valid = JSONSerialization.isValidJSONObject(parameters) // true
print (valid)
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) // pass dictionary to nsdata object and set it as request body
} catch let error {
print(error)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
// 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
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(json)
// handle json...
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
let alertMessage = UIAlertController(title: "Saved!", message: "We have recorded your information", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title:"Okay", style: UIAlertActionStyle.default, handler: nil)
alertMessage.addAction(action)
self.present(alertMessage, animated: true, completion: nil)
}
I solved it by first storing them in a variable
var TITLE = UserDefaults.standard.value(forKey: "Title")
var GN = UserDefaults.standard.value(forKey: "GivenNames")
var LN = UserDefaults.standard.value(forKey: "LastName")
Then I placed them in a parameter and that's done. It was so obvious that I can't believe I didn't solve it sooner
#IBAction func save(_ sender: Any){
let parameters = ["Tax Year": TaxYear, "Title": TITLE, "first-name": GN, "sur-name": LN]

How to make this POST request with different objects?

Overview:
I am trying to make a POST request, which I have done before with only strings. This time, I have a few variables, being: String, Int, and Bool.
Error:
Cannot assign value of type [String : Any] to type Data
Line causing the error:
request.httpBody = paramToSend
Question:
How to convert a Dictionary into Data ?
Complete Code:
func sendComplimentAPI (message: String, recipient: Int, isPublic: Bool) {
let url = URL(string: "https://complimentsapi.herokuapp.com/compliments/send/")
let session = URLSession.shared
let preferences = UserDefaults.standard
let request = NSMutableURLRequest(url: url!)
request.addValue("\(preferences.object(forKey: "token") as! String)", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
let paramToSend = ["message":message,"recipient":recipient,"is_public":isPublic] as [String : Any]
request.httpBody = paramToSend
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
guard let _:Data = data else {return}
let json:Any?
do{json = try JSONSerialization.jsonObject(with: data!, options: [])}
catch {return}
guard let server_response = json as? NSDictionary else {return}
if let session_data = server_response["id"] as? String {
print("worked")
//do something
/*DispatchQueue.main.async (
execute:
)*/
} else {
print("error")
}
})
task.resume()
}
EDIT:
I have tried this new code and it is still not posting to the server. I am attaching what I changed and also writing what the console shows for the two prints I have it do.
let paramToSend = ["message":writeTextField.text!,"recipient":1,"is_public":isPrivate] as [String : Any] //messageString + recipientString + isPublicString
do {
var serialized = try JSONSerialization.data(withJSONObject: paramToSend, options: .prettyPrinted)
print(serialized)
request.httpBody = serialized
print(request.httpBody)
} catch {
print("found a problem")
}
The console returns (for serialized and then the HTTP body):
113 bytes
Optional(113 bytes)
Is that optional causing the problem? How do I fix it?
To convert Dictionary to Data, use JSONSerialization.data:
Solution:
JSONSerialization.data(withJSONObject: paramToSend, options: .prettyPrinted)
Check the request:
Print the request and see if it matches your expectation
Reading the response:
//Check if there is any error (check if error != nil)
//Examine the response
let statusCode = (response as? HTTPURLResponse)?.statusCode
let statusCodeDescription = (response as? HTTPURLResponse)?.localizedString(forStatusCode: httpResponse.statusCode)
//Check Data
if let data = data {
let dataString = String(data: data, encoding: String.Encoding.utf8)
}
It turns out I needed to add a simple additional header to get the whole thing to work.
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
This is probably why it was not understanding the dictionary I was sending it

I need to parse this JSON response make with http request in swift

This is my script in php to have a Json response
<?php
include "dbconnect.php";
$id = $_POST['id'];
$uname = $_POST['uname'];
try {
$queryExistingBike = "SELECT StatoBici, Username FROM BICI INNER JOIN UTENTE ON utenteKEY = KEYutente WHERE (IdBike = '$id')";
$search = $connection->query($queryExistingBike);
//print_r ($search);
} catch (Exception $ex) {
echo $ex->getMessage();
}
$dati = $search->fetch_assoc();
if ($dati["Username"] == "$uname") {
$dati['Username'] = "true";
} else {
$dati['Username'] = "false";
}
//print_r($dati);
print json_encode($dati);
?>
This is the Json response from php script
{"StatoBici":"ok","Username":"false"}
This is the code in swift to make a http post request to web service
func jsonResponse(){
var request = URLRequest(url: URL(string: "http://bike1010.com/webservice/getBikeData.php")!)
request.httpMethod = "POST"
let postString = "id=2017&uname=admin" // Your parameter
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
}
let responseString = try? JSONSerialization.jsonObject(with: data, options:[])
print(responseString)
}
task.resume()
}
The output into Xcode
Optional({
StatoBici : Ok
Username : Tue
})
if that's what you wanted to achieve:
let responseString = try? JSONSerialization.jsonObject(with: data, options:[]) as? [String:Any]
print(responseString)
//simple example for receiving each field from response
let statoBici:String = responseString["StatoBici"] as! String
let username:Bool = responseString["Username"] as! Bool
print("StatoBici received: \(statoBici), username received: \(username)")
As Wojcik mentioned in comment you already have parse JSON. Your responseString is actually parsed object. You can access values as:
if let obj = responseString as? NSDictionary {
let StatoBici = obj.value(for : "StatoBici") as! String
let okValue = obj.value(for : "OK") as! String // If OK is bool use bool
}

Swift: send POST request with JSONEncoder encoded data does not work

I am using the JSONEncoder that has been provided with Swift4.
I have a class called Customer that uses the Codable protocol. Inside of Customer there are four Strings.
class Customer: Codable {
var title: String
var firstName: String
var lastName: String
var email: String
}
Reading JSON with a GET Request works fine.
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
}
guard let data = data else { return }
do {
let customer = try JSONDecoder().decode(Customer.self, from: data)
DispatchQueue.main.async {
print("\(customer.title)")
print("\(customer.firstName)")
print("\(customer.lastName)")
print("\(customer.email)")
}
} catch let jsonError {
print(jsonError)
}
}.resume()
However when I start to do a POST request I am lost:
First set up the request object:
let urlString = "http://localhost:8000/customer"
guard let url = URL(string: urlString) else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
let customer = Customer()
customer.title = "Mr"
customer.firstName = "Chuck"
customer.lastName = "Norris"
customer.email = "chuck.norris#awsome.com"
let encodedData = try? JSONEncoder().encode(customer)
print(String(data: encodedData!, encoding: .utf8)!) //<- Looks as intended
// Output is {"firstName":"Chuck","lastName":"Norris","title":"MR","email":"chuck.norris#awesome.com "}
Now send it out
request.httpBody = encodedData //
URLSession.shared.dataTask(with: request, completionHandler: {(data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.data(withJSONObject: data, options: [])
print(json)
}catch {
print(error)
}
}
})
In return I receive the message "The given data was not valid JSON."
So, my assumption is that I simply can not just put the encoded JSON data into the http body of my request.
Browsing through some articles about URLSession and JSON I found that it seems that I need to serialize my encoded JSON:
var json: Any?
if let data = encodedData {
json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
}
Now, I don't know how to proceed. First I do not understand why I should serialize my JSON to something that can not simply put into a httpBody.
Because JSONSerialization.jsonObject produces Any? and not Data.
Update
Now, I was able to successfully send my data to my server. I am still trying to understand what was wrong - because I did not changed anything (except for the removal of the JSONSerialization call inside the completion Handler. I will investigate further...
...And .resume had been missing. :-)