How to use KingFisher or AlamofireImage library with auth token? - swift

I have a tableView with customCells and I need to load pictures from a REST API (access with auth token).
As Im a noob in swift I came across some libraries and it seems KingFisher or AlamofireImage are good ones for asynch loading and caching images retrieved from an API call.
But since my API here has an access token, how can that being passed into this request?
//image handling with kingfisher
if let imgView = cell.schoolCoverImage {
imgView.kf_setImageWithURL(
NSURL(string: "")!,
placeholderImage: nil,
optionsInfo: nil,
progressBlock: nil,
completionHandler: { (image, error, CacheType, imageURL) -> () in
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) }
)
}
For example in Alamofire there is the field headers where the access token can be passed
//Sample API call with Alamofire
Alamofire.request(
.GET,
baseURL+schools+nonAcademicParameter,
headers: accessToken
)
.responseJSON { response in
switch response.result {
case .Success(let value):
completionHandler(value, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}
But with AlamofireImage the field headers seems not to be available
//Image request with AlamofireImage
Alamofire.request(
.GET,
"https://httpbin.org/image/png"),
headers: ["Authorization" : "Bearer fbzi5u0f5kyajdcxrlnhl3zwl1t2wqaor"] //not available
.responseImage { response in
debugPrint(response)
print(response.request)
print(response.response)
debugPrint(response.result)
if let image = response.result.value {
print("image downloaded: \(image)")
}
}

You could just use the request modifier and pass it as an option to Kingfisher's setting image method. Like this:
let modifier = AnyModifier { request in
var r = request
r.setValue("Bearer fbzi5u0f5kyajdcxrlnhl3zwl1t2wqaor", forHTTPHeaderField: "Authorization")
return r
}
imageView.kf.setImage(with: url, placeholder: nil, options: [.requestModifier(modifier)])
See the wiki page of Kingfisher for more.

import Foundation
var semaphore = DispatchSemaphore (value: 0)
var request = URLRequest(url: URL(string: "<your url>")!,timeoutInterval: Double.infinity)
request.addValue("Bearer <your token>", forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
print(String(data: data, encoding: .utf8)!)
semaphore.signal()``
}
task.resume()
semaphore.wait()

I figured that out eventually
create the following in viewdidload()
//create custom session with auth header
let sessionConfig =
NSURLSessionConfiguration.defaultSessionConfiguration()
let xHTTPAdditionalHeaders: [String : String] =
self.restApi.accessToken
sessionConfig.HTTPAdditionalHeaders = xHTTPAdditionalHeaders
self.imageDownloader = ImageDownloader(
configuration: sessionConfig,
downloadPrioritization: .FIFO,
maximumActiveDownloads: 4,
imageCache: AutoPurgingImageCache()
)
use it in cellforrowatindexpath:
let URLRequest = NSURLRequest(URL: NSURL(string: "https:/xxx.com/olweb/api/v1/schools/"+schoolIdString+"/image/"+ImageNameString)!)
self.imageDownloader.downloadImage(URLRequest: URLRequest) { response in
print(response.request)
print(response.response)
debugPrint(response.result)
if let image = response.result.value {
print("here comes the printed image:: ")
print(image)
print(schoolIdString)
cell.schoolCoverImage.image = image
cell.schoolBiggerImage.image = image
} else {
print("image not downloaded")
}
}

Related

How to use json response as parameter in another api post call?

I make a GET call and receive a json response. I need to use that json response as one parameter for a subsequent POST call.
I’ve tried to:
-parse the data into an object and pass the [object] as parameter
-parse the data into a string and pass the string as parameter
-parse the data as dict and pass the dict as parameter
but it’s not working, I believe it’s a data thing or a secret I’m missing
How do you use a json response as parameter for a subsequent api call?
//MARK: - PIXLAB facedetect
func facedetectGET(uploadedUrl: String) {
var urlComponents = URLComponents(string: "https://api.pixlab.io/facedetect")
urlComponents?.queryItems = [
URLQueryItem(name: "img", value: uploadedUrl),
URLQueryItem(name: "key", value: Constants.pixlabAPIkey),
]
let url = urlComponents?.url
if let url = url {
// Create URL Request
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 10.0)
request.httpMethod = "GET"
request.addValue("Bearer \(Constants.pixlabAPIkey)", forHTTPHeaderField: "Authorization")
// Get URLSession
let session = URLSession.shared
// Create Data Task
let dataTask = session.dataTask(with: request) { (data, response, error) in
// Check that there isn't an error
if error == nil {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: [])
//make a dict
//let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String: Any]
print("SUCCESS: image detected")
print(json)
//make json a string utf8 so it can be used as parameter in next call
//let jsonString = String(data: json as! Data, encoding: .utf8)
//let jsonData = json.data(using: .utf8)!
//parse json
//decode the json to an array of faces
let faces: [Face] = try! JSONDecoder().decode([Face].self, from: data!)
let facesString = String(faces)
//use dispatch main sync queue??"bottom": Int,
//mogrify call
mogrify(uploadedUrl: uploadedUrl, cord: faces)
}
catch {
print(error)
}
}
}
// Start the Data Task
dataTask.resume()
}
}
//MOGRIFY CALL
func mogrify(uploadedUrl: String, cord: Any) {
let mogrifyurl = URL(string: "https://api.pixlab.io/mogrify")!
//let param: [Face] = result.faces
let param: [String: Any] = ["img": uploadedUrl, "cord": cord]
var request = URLRequest(url: mogrifyurl)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer \(Constants.pixlabAPIkey)", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
request.httpBody = try! JSONSerialization.data(withJSONObject: param, options: [])
URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
print(error!)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!)
print(json)
} catch {
print("error")
}
}.resume()
}
this is how pretty the response looks
enter image description here
and this is how it looks when I pass it as parameter
enter image description here
A POST needs the body as Data. If you're just forwarding the body of the GET to the body of the POST, it would be easiest to leave it as Data.
You could also deserialize the response into an object in your get, and then re-serialize it back into Data in the POST code, but why?
I did lots of white magic, voodoo and lots of praying (aka try and error) and I made it work…
basically decoded the json data, then got an array subdata and encode it back into a data variable as input for the post call
maybe there is an easier and more elegant way but this works....
do {
//decode the json to an array of faces
let cord = try! JSONDecoder().decode(Cord.self, from: data!)
print(cord.faces)
let cordData = try! JSONEncoder().encode(cord.faces)
let coordinates = try JSONSerialization.jsonObject(with: cordData, options: [])
print(coordinates)
//mogrify call
mogrify(uploadedUrl: uploadedUrl, cord: coordinates)
} catch {
print(error)
}
post call
//MOGRIFY CALL
func mogrify(uploadedUrl: String, cord: Any) {
let mogrifyurl = URL(string: "https://api.pixlab.io/mogrify")!
// let param: [Face] = result.faces
let param: [String: Any] = ["img": uploadedUrl, "key": Constants.pixlabAPIkey, "cord": cord]
var request = URLRequest(url: mogrifyurl)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer \(Constants.pixlabAPIkey)", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
request.httpBody = try! JSONSerialization.data(withJSONObject: param, options: [])
URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
print(error!)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!)
print("MOGRIFY response")
print(json)
} catch {
print("error")
}
}.resume()
}

Stripe: Registered webhook but still getting "Not a Valid URL" error

I seem to be running into an error each time I try to make a payment transaction where Stripe declines the operation by saying "Not a valid URL". The client-side is in Swift, while the server is in Python, deployed on Heroku.
A suggestion I saw on another post was to register my server webhook with my Stripe account, which I did, but it doesn't seem to solve the problem.
For reference, here is my createPaymentIntent function:
func createPaymentIntent(dict: [String:Any]) {
let url = self.baseURL.appendingPathComponent("create-payment-intent")
let params = dict
let jsondata = try? JSONSerialization.data(withJSONObject: params)
var clientSecretOut = ""
var request = URLRequest(url: url)
request.httpMethod = "POST"
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 response = response as? HTTPURLResponse,
response.statusCode == 200,
let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any],
let clientSecret = json["clientSecret"] as? String else {
let message = error?.localizedDescription ?? "Failed to decode response from server."
print("Error: ", message)
return
}
clientSecretOut = clientSecret
print("client out inside: ", clientSecretOut)
self?.clientSecretFinal = clientSecret
})
task.resume()
}
And here is the place where the error seems to be called– my didCreatePaymentResultFunction:
func paymentContext(_ paymentContext: STPPaymentContext, didCreatePaymentResult paymentResult: STPPaymentResult, completion: #escaping STPPaymentStatusBlock) {
let paymentIntentParams = STPPaymentIntentParams(clientSecret: self.clientSecretFinal)
paymentIntentParams.configure(with: paymentResult)
paymentIntentParams.returnURL = "meURLStripeTest://"
STPPaymentHandler.shared().confirmPayment(withParams: paymentIntentParams, authenticationContext: paymentContext) { status, paymentIntent, error in
switch status {
case .succeeded:
print("success")
completion(.success, nil)
case .failed:
print("cant", error)
completion(.error, error)
case .canceled:
completion(.userCancellation, nil)
#unknown default:
completion(.error, nil)
}
}
}
Thanks for your help!
The problem is in this line:
paymentIntentParams.returnURL = "meURLStripeTest://"
The returnURL has to be a valid URL or application URI scheme, in your case it's neither. See here on how to create an application URI scheme for your app.

Call Rest API from Swift3

I trying to send a POST request in swift for example :
url = "http://localhost:9080/mfp/api/az/v1/token"
Headers :
Authorization = "Basic UGlua0NhclBhc3NlbmdlcjoxMjM0"
Content-Type = "application/x-www-form-urlencoded"
Body :
grant_type = client_credentials
scope = RegisteredClient messages.write push.application.com.XXX
What's simple way to do it ?
I've tried by use IBMMobileFirstPlatformFoundation SDK, it's return error "Can't not connect to server",but i'm sure that the connect still good... Here's my code :
let urlString = "http://localhost:9080/mfp/api/az/v1/token"
let url1 = URL(string: urlString)
let request1 = WLResourceRequest(url: url1! as URL, method: WLHttpMethodPost)!
request1.addHeaderValue("Basic UGlua0NhclBhc3NlbmdlcjoxMjM0" as NSObject, forName: "Authorization")
request1.addHeaderValue("application/x-www-form-urlencoded" as NSObject, forName: "Content-Type")
request1.send(withBody: "{\"grant_type\":\"client_credentials\",\"scope\":\"RegisteredClient messages.write push.application.com.XXX\"}", completionHandler: { (response, error) in
if error == nil {
print("Response : ")
print(response)
} else {
print("Error : ")
print(error)
}
})
You can use Alamofire as ZassX suggested or you can use URLSession.
I have some code as an example:
func postRequest(toUrl url: String, accessKey: String?, completion: #escaping(Data?, HTTPURLResponse?, Error?, AnyObject?) -> Void){
let requestUrl = NSURL(string: url)
let request = NSMutableURLRequest(url: requestUrl! as URL)
if accessKey != nil {
request.setValue("\(accessKey!)", forHTTPHeaderField: "Authorization")
}
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = yourBody
URLSession.shared.dataTask(with: request as URLRequest, completionHandler: { (data,response,error) in
if let content = data{
do{
let myJSON = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
completion(data as Data?, response as? HTTPURLResponse, error, myJSON)
}
catch{
print("JSON ERROR")
}
}else{
completion(data as Data?, response as? HTTPURLResponse, error, nil)
}
}).resume()
}
First, you don't manually manage the security token when you're using the MobileFirst SDK, it's handled automatically.
Next, WLResourceRequest() takes a URL that is relative to the MobileFirst server URL (http://localhost:9080/mfp, in your case). You can see that "base" URL in your mfpclient.plist file.
Your code will then look something like
let request = WLResourceRequest(
URL: NSURL(string: "/adapters/MyAdapter/myResource"),
method: WLHttpMethodGet
)
See https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/8.0/application-development/resource-request/ios/

How to convert this to a POST call with a JSON serialized Object

I have tried Alamofire, I have tried it with all my heart. It just does not work for me. I finally got http GET working, but I need to get http POST working. Our POST API's take a Request object that has all the necessary data in it. I have requested the backend developers to provide me with a KEY-VALUE pair JSON (no embedded objects/arrays) so that I can use a Dictionary in my swift code convert that to json and send the request. All I need is now to convert the below code to POST.
My earlier questions that did not help much.
NSInvalidArgumentException Invalid type in JSON write DemographicsPojo
Swift 3.0, Alamofire 4.0 Extra argument 'method' in call
I have given up on Alamofire. I want to use Foundation classes. Simple basic and fundamental way of life :).
func callWebService(url : String) {
// Show MBProgressHUD Here
var config :URLSessionConfiguration!
var urlSession :URLSession!
config = URLSessionConfiguration.default
urlSession = URLSession(configuration: config)
// MARK:- HeaderField
let HTTPHeaderField_ContentType = "Content-Type"
// MARK:- ContentType
let ContentType_ApplicationJson = "application/json"
//MARK: HTTPMethod
let HTTPMethod_Get = "GET"
let callURL = URL.init(string: url)
var request = URLRequest.init(url: callURL!)
request.timeoutInterval = 60.0 // TimeoutInterval in Second
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
request.addValue(ContentType_ApplicationJson, forHTTPHeaderField: HTTPHeaderField_ContentType)
request.httpMethod = HTTPMethod_Get
let dataTask = urlSession.dataTask(with: request) { (data,response,error) in
if error != nil{
print("Error **")
return
}
do {
let resultJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
print("Result",resultJson!)
} catch {
print("Error -> \(error)")
}
}
dataTask.resume()
print("..In Background..")
}
Just pass JSON string and the API URL to this function. Complete code for POST.
func POST(api:String,jsonString:String,completionHandler:#escaping (_ success:Bool,_ response:String?,_ httpResponseStatusCode:Int?) -> Void) {
let url = URL(string: api)
var request: URLRequest = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField:"Content-Type")
request.timeoutInterval = 60.0
//additional headers
if let token = Helper.readAccessToken() {
request.setValue("\(token)", forHTTPHeaderField: "Authorization")
}
let jsonData = jsonString.data(using: String.Encoding.utf8, allowLossyConversion: true)
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) {
(data: Data?, response: URLResponse?, error: Error?) -> Void in
var responseCode = 0
if let httpResponse = response as? HTTPURLResponse {
responseCode = httpResponse.statusCode
print("responseCode \(httpResponse.statusCode)")
}
if error != nil {
completionHandler(false, error?.localizedDescription,nil)
} else {
let responseString = String(data: data!, encoding: .utf8)
completionHandler(true, responseString, responseCode)
}
}
task.resume()
}

Get request return error code 405 - method not allowed

I've wrote a function for GET request from rest and it says that i have method not allowed - code 405 which is werid and i can not find solution for that.
I am doing GET via current token which was assigned to the user after logged in.
Could someone have a look on the code and tell me what might be wrong ?
func getRequest() -> Void {
let json: [String: Any] = ["token": SessionMenager.Instance.token]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// create post request
let url = URL(string: MY_URL)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
// insert json data to the request
request.httpBody = jsonData
request.setValue("application/json;charest=utf-8", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
if let httpResponse = response as? HTTPURLResponse {
print("GET : code - \(httpResponse.statusCode)")
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
} else{
print(error.debugDescription)
}
}
task.resume()
}
Thanks in advance!!