How do i pass the data from my parser out the function - swift

I need to pass the data of the "object" in my Parser outside the function.
I tried to make a multidim array and store it to it but i can only access it inside the function, it comes empty outside when i print it.
ApiParser.parseFuction(strUrl: Constants.URL.Global + "HR/EndOfDay/GetAllEndOfReports", method: "GET", token: "", params: [String : AnyObject]()) { (status, object) in
let data = object["value"] as! [[String: AnyObject]]
let jsonData = try? JSONSerialization.data(withJSONObject: data)
let test = try! JSONDecoder().decode([EODDataContainer].self, from: jsonData!)
print(test)
} // this is the code inside the viewdidload
class ApiParser: NSObject {
class func parseFuction(strUrl: String, method: String, token: String, params: [String : AnyObject]?, postCompleted: #escaping (_ statusCode: Int, _ object: [String: AnyObject]) ->()) {
let className = "--- ApiParser: ------->>>"
let url = URL(string: strUrl)
var request = URLRequest(url: url!)
request.httpMethod = method
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
if method == "POST" || method == "PUT" {
let jsonData = try? JSONSerialization.data(withJSONObject: params!)
request.httpBody = jsonData
}
let sessionConfig = URLSessionConfiguration.default
sessionConfig.timeoutIntervalForRequest = 300.0
sessionConfig.timeoutIntervalForResource = 300.0
let session = URLSession(configuration: sessionConfig)
session.dataTask(with: request) { (data, response, err) in
print(request)
guard let httpResponse = response as? HTTPURLResponse else { return }
let statusCode = httpResponse.statusCode
print("statusCode ---->>> \(statusCode)")
DispatchQueue.main.async {
guard let data = data else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String: AnyObject]
postCompleted(statusCode, json)
} catch let jsonErr {
print("Serializing jsonError \(type(of: jsonErr))", jsonErr._code)
postCompleted(jsonErr._code, [String: AnyObject]())
}
}
}.resume()
}
} //this is my api parser class
I want to store the "test" variable inside the "twoDimensionalArray"

In the ViewController class :
var test : [EODDataContainer]?
override func ViewDidLoad() {
super.viewDidLoad()
ApiParser.parseFuction(strUrl: Constants.URL.Global + "HR/EndOfDay/GetAllEndOfReports", method: "GET", token: "", params: [String : AnyObject]()) { (status, object) in
let data = object["value"] as! [[String: AnyObject]]
let jsonData = try? JSONSerialization.data(withJSONObject: data)
self.test = try! JSONDecoder().decode([EODDataContainer].self, from: jsonData!)
print(test)
}

Related

Post request with JSON body in Swift

I have been looking for a similar solution for a long time but I can't find it.
I have to make a post request for my Stripe server.
For that I have to send a request with a JSON in Body : {"price" : 50}.
I can't figure out what's wrong.
Thank you
override func viewDidLoad() {
super.viewDidLoad()
checkoutButton.addTarget(self, action: #selector(didTapCheckoutButton), for: .touchUpInside)
checkoutButton.isEnabled = false
let parameters: [String: Any] = [
"price": "50",
]
let jsonData = try? JSONSerialization.data(withJSONObject: parameters)
var request = URLRequest(url: backendCheckoutUrl)
request.httpMethod = "POST"
request.setValue("\(String(describing: jsonData?.count))", forHTTPHeaderField: "Content-Length")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in
guard let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any],
let customerId = json["customer"] as? String,
let customerEphemeralKeySecret = json["ephemeralKey"] as? String,
let paymentIntentClientSecret = json["paymentIntent"] as? String,
let publishableKey = json["publishableKey"] as? String,
let self = self else {
return
}
STPAPIClient.shared.publishableKey = publishableKey
var configuration = PaymentSheet.Configuration()
configuration.merchantDisplayName = "Example, Inc."
configuration.applePay = .init(
merchantId: "com.foo.example", merchantCountryCode: "US")
configuration.customer = .init(
id: customerId, ephemeralKeySecret: customerEphemeralKeySecret)
configuration.returnURL = "....."
configuration.allowsDelayedPaymentMethods = true
self.paymentSheet = PaymentSheet(
paymentIntentClientSecret: paymentIntentClientSecret,
configuration: configuration)
DispatchQueue.main.async {
self.buyButton.isEnabled = true
}
})
task.resume()
}

urlrequest not sending post request

Hi i am new to IOS App developement.
My code is
func sendRequest<T: Decodable>(api: String, parameters: [String: String]? = nil, outputBlock: #escaping (T) -> () ) {
guard let url = URL(string: "http://xxyyzz.com/appRegister.php") else {return}
print("hitting : -", url.absoluteString)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let newparam = ["name": "rr", "pass": "123456", "email": "rr#rr.com", "passConfirm":"123456"]
let httpBody = try? JSONSerialization.data(withJSONObject: newparam)
request.httpBody = httpBody
if let data = request.httpBody, let str = String(data: data, encoding: String.Encoding.utf8) {
print(str)
}
URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
DispatchQueue.main.async {
Indicator.shared.hideProgressView()
if let err = error {
print(err.localizedDescription)
return
}
guard let data = data else {return}
do {
let obj = String(data: data, encoding: String.Encoding.utf8)
print(obj ?? "oberrrrr")
}
}
}.resume()
}
and console printed result as per code is below
hitting : - http://xxyyzz.com/appRegister.php
{"email":"rr#rr.com","passConfirm":"123456","name":"rr","pass":"123456"}
{"error":"Please enter all fields."}
url and parameters works well on postman that means their is something missing in my code.
just to answer the problem if anyone else faces this.
this code is fine but the problem was with php web-service as the backend developer was not accepting json values as parameter instead form data was need to send.
So, two types of fix can be made here
accept json at backend by adding :-
$postdata = file_get_contents("php://input");
$request = json_decode($postdata, true);
send form data instead json
func sendRequest<T: Decodable>(api: String, parameters: [String: Any]? = nil, outputBlock: #escaping (T) -> () ) {
guard let url = URL(string: api) else {return}
print("hitting : -", url.absoluteString)
var request = URLRequest(url: url)
if let parameters = parameters {
request.httpMethod = "POST"
var postArr = [String]()
for(key, value) in parameters
{
postArr.append(key + "=\(value)")
}
let postString = postArr.map { String($0) }.joined(separator: "&")
request.httpBody = postString.data(using: .utf8)
if let data = request.httpBody, let str = String(data: data, encoding: String.Encoding.utf8) {
print(str)
}
}
URLSession.shared.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
Indicator.shared.hideProgressView()
if let err = error {
print(err.localizedDescription)
return
}
guard let data = data else {return}
do {
let obj = try JSONDecoder().decode(T.self, from: data)
outputBlock(obj)
} catch let jsonErr {
print(jsonErr)
}
}
}.resume()
}

How to return songs from Apple Music API?

I need add a new function that returns songs from Apple Music API. The code below returns nil however, it works for Album ID. I modified the code from APIClient.swift. See source for details.
It returns song(id:completion:) JSON Decode Failed.
Source: https://github.com/shingohry/AppleMusicSearch
SongModel.swift
func song(id: String, completion: #escaping (Resource?) -> Swift.Void) {
let completionOnMain: (Resource?) -> Void = { resource in
DispatchQueue.main.async {
completion(resource)
}
}
guard let url = URL(string: "https://api.music.apple.com/v1/catalog/\(APIClient.countryCode)/songs/\(id)") else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.addValue("Bearer \(APIClient.developerToken)",
forHTTPHeaderField: "Authorization")
data(with: request) { data, error -> Void in
guard error == nil else {
print(#function, "URL Session Task Failed", error!)
completionOnMain(nil)
return
}
guard let jsonData = try? JSONSerialization.jsonObject(with: data!),
let dictionary = jsonData as? [String: Any],
let dataArray = dictionary["data"] as? [[String: Any]],
let songDictionary = dataArray.first,
let songData = try? JSONSerialization.data(withJSONObject: albumDictionary),
let album = try? JSONDecoder().decode(Resource.self, from: songData) else {
print(#function, "JSON Decode Failed");
completionOnMain(nil)
return
}
completionOnMain(song)
}
}

Callback syntax in swift 3

I am trying to create a callback on swift 3 but haven't had any luck so far. I was taking a look at this question: link which is similar, but the answer gives me an error.
Basically I have an API struct with a static function that I need to have a callback.
import UIKit
struct API {
public static func functionWithCallback(params: Dictionary<String, String>, success: #escaping ((_ response: String) -> Ticket), failure: #escaping((_ error:String) -> String) ) {
let app_server_url = "http://api.com" + params["key"]!
let url: URL = URL(string: app_server_url)!
var request: URLRequest = URLRequest(url: url)
request.httpMethod = "POST"
do {
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/json charset=utf-8", forHTTPHeaderField: "Content-Type")
request.addValue("application/json charset=utf-8", forHTTPHeaderField: "Accept")
let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else {
return
}
guard let data = data else {
return
}
DispatchQueue.main.async {
do {
let json = try JSONSerialization.jsonObject(with: data) as! [String: Any]
print(json)
var message = ""
if let result = json["result"] as? String {
if(result == "success") {
//attempt to call callback gives me an error: extra argument in call
success("") {
let ticket = json["ticket"] as! NSDictionary
var date = ticket["date"] as! String
var ticket: Ticket = nil
ticket.setDate(date: date)
return ticket
}
}
else {
message = json["message"] as! String
print(message)
}
} catch let error {
print(error.localizedDescription)
let description = error.localizedDescription
if let data = description.data(using: .utf8) {
do {
let jsonError = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
let message = jsonError?["message"] as! String
} catch {
}
}
}
}
})
task.resume()
}
}
So I basically can't call the callback success because it gives me an error: Extra argument in call. Any idea on how to fix it?
My goal is to call:
API.functionWithCallback(params: params, success() -> Ticket {
//do something with the returned ticket here
},
error() -> () {
//do something with the error message here
}
)
I believe you have it wrong on how to use call back closures, from what I can understand of your question you want to do something with the ticket in the call back closure and to do that it should be a parameter of the closure not the return type of the closure.
Replace your function declaration with this:
public static func functionWithCallback(params: Dictionary<String, String>, success: #escaping ((_ response: String, _ ticket: Ticket) -> Void), failure: #escaping((_ error:String) -> Void) ) {
And inside the function replace this:
success("") {
let ticket = json["ticket"] as! NSDictionary
var date = ticket["date"] as! String
var ticket: Ticket = nil // Im not sure what you are trying to do with this line but this will definitely give an error
ticket.setDate(date: date)
return ticket
}
With:
let ticket = json["ticket"] as! NSDictionary
var date = ticket["date"] as! String
var ticket: Ticket = nil // fix this line
ticket.setDate(date: date)
success("",ticket)
And then you can call the function like this:
API.functionWithCallback(params: params, success: { response, ticket in
// you can use ticket here
// and also the response text
}) { errorMessage in
// use the error message here
}
Try this :
func uploadImage(api: String,token : String, methodType : String, requestDictionary: [String:AnyObject],picData:[Data], successHandler: #escaping (AnyObject) -> Void,failureHandler: #escaping (NSError) -> Void)
{
if Common_Methods.Reachability1.isConnectedToNetwork() == false
{
let del :AppDelegate = (UIApplication.shared.delegate as? AppDelegate)!
let nav : UINavigationController = (del.window?.rootViewController as? UINavigationController)!
let alert = UIAlertController(title: "", message: "The Internet connection appears to be offline" , preferredStyle: UIAlertControllerStyle.alert)
// Create the actions
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default)
{
UIAlertAction in
}
alert.addAction(okAction)
nav.present( alert, animated: true, completion: nil)
return
}
let apiUrl = "\(KbaseUrl)\(api)"
let session = URLSession.shared
let url: NSURL = NSURL(string: apiUrl as String)!
print(url)
let request = NSMutableURLRequest(url: url as URL)
request.httpMethod = methodType
let boundary = NSString(format: "---------------------------14737809831466499882746641449") as String
//-------- add token as perameter and set a check if token not nill then set token in header -------
if(token.characters.count > 0)
{
request.setValue(token, forHTTPHeaderField: "x-logintoken")
}
request.setValue("Keep-Alive", forHTTPHeaderField: "Connection")
request.setValue("multipart/form-data; boundary="+boundary, forHTTPHeaderField: "Content-Type")
let data = createBodyWithParameters(parameters: requestDictionary, filePathKey:nil, imageDataKey: picData.count > 0 ? picData : [], boundary: boundary)
print(data)
request.httpBody = data
let task = session.dataTask(with: request as URLRequest) { data, response, error in
// handle fundamental network errors (e.g. no connectivity)
guard error == nil && data != nil else {
successHandler(data as AnyObject )//completion(data as AnyObject?, error as NSError?)
print(error)
DispatchQueue.main.async {
Common_Methods.hideHUD(view: (topVC?.view)!)
}
return
}
// check that http status code was 200
if let httpResponse = response as? HTTPURLResponse , httpResponse.statusCode != 200 {
do {
let responseObject = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary
if let responseDictionary = responseObject as? [String:AnyObject]
{
if responseDictionary["statusCode"] as! Int == 401
{
// self.objDelegate.sessionExpire(msgStr: "Session Expired. Please login again to continue.")
}
else
{
//completion(String(data: data!, encoding: String.Encoding.utf8) as AnyObject?, nil)
}
}
} catch let error as NSError {
print(error)
DispatchQueue.main.async {
Common_Methods.hideHUD(view: (topVC?.view)!)
}
// completion(String(data: data!, encoding: String.Encoding.utf8) as AnyObject?, nil)
}
}
// parse the JSON response
do {
DispatchQueue.main.async {
Common_Methods.hideHUD(view: (topVC?.view)!)
}
let responseObject = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary
successHandler(responseObject! )
} catch let error as NSError {
DispatchQueue.main.async {
Common_Methods.hideHUD(view: (topVC?.view)!)
}
// completion(String(data: data!, encoding: String.Encoding.utf8) as AnyObject?, error)
failureHandler(error)
}
}
task.resume()
// return task
}
and function Call is :
WebService.sharedInstance.uploadImage(api: KEditEmployerProfile,token: token,methodType: "PUT", requestDictionary: parameters1 as! [String : AnyObject], picData: [imageData as Data], successHandler: { (responseObject) in
print(responseObject)
}) { (error) in
print(error)
}
}

swift URLRequest doesn't send parameters

In the code below
let bodyData = "?sub=\(id)&name=User&email=test#test.com"
let url = NSURL(string: "https://httpbin.org/get");
let request:NSMutableURLRequest = NSMutableURLRequest(url:url as! URL)
request.httpMethod = "GET"
request.httpBody = bodyData.data(using: String.Encoding.utf8);
NSURLConnection.sendAsynchronousRequest(request as URLRequest, queue: OperationQueue.main)
{
(response, data, error) in
if let HTTPResponse = response as? HTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
// Yes, Do something.
let json = try? JSONSerialization.jsonObject(with: data!, options: [])
if let dictionary = json as? [String: Any] {
let args = dictionary["args"]
NSLog("args:\(args)")
for (key, value) in dictionary{
NSLog("key:\(key) value:\(value)")
}
}
}
}
}
id is a string passed in to the function.
It has valid data returned, but the test site/url also returns in json format any parameters you send it. But this snippet of code seems to not be sending the query parameters defined in bodyData and I can't figure out why.
If a GET request is used the parameters are appended to the URL and an explicit URLRequest is not needed at all.
This code is native Swift 3 and uses contemporary API:
let id = 12
let bodyData = "?sub=\(id)&name=User&email=test#test.com"
let url = URL(string: "https://httpbin.org/get" + bodyData)!
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:Any],
let args = json["args"] as? [String:Any] {
print("args:\(args)")
for (key, value) in args{
print("key:\(key) value:\(value)")
}
}
} catch {
print(error)
}
}.resume()