New to Swift and trying to write a login screen for my app.
My controller:
#IBAction func loginButton(sender: UIButton) {
let emailAddress = emailTextField.text
let password = passwordTextField.text
let api = Api()
api.authenticate(emailAddress!, password: password!)
}
Api class:
class Api {
func authenticate(username: String, password: String) -> Bool {
var params = [String: String]()
params["username"] = username
params["password"] = password
params["grant_type"] = "password"
var headers = [String: String]()
headers["Content-Type"] = "application/x-www-form-urlencoded"
post("authenticate", params: params, headers: headers) {data, response in
// do something
}
}
func post(location: String, params: [String: String], headers: [String: String], callback: ((data: NSString!, response: NSHTTPURLResponse) -> Void)) {
let request = NSMutableURLRequest()
let session = NSURLSession.sharedSession()
request.URL = NSURL(string: Configuration.apiBaseUrl + location)
request.HTTPMethod = "POST"
request.HTTPBody = NSString(string: getPostBody(params)).dataUsingEncoding(NSUTF8StringEncoding)
request.addValue("Basic " + Configuration.apiAuthorization, forHTTPHeaderField: "Authorization")
for (key, value) in headers {
request.addValue(value, forHTTPHeaderField: key)
}
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let data = NSString(data: data!, encoding: NSUTF8StringEncoding)
let httpResponse = response as! NSHTTPURLResponse
callback(data: data, response: httpResponse)
return
})
task.resume()
}
}
As I plan to add more API methods after authentication, I want generic POST/PUT/GET/DELETE methods. I am trying to understand how I can best set up the callbacks in Swift so the post call in the authenticate method can return true/false and show like a dialog on the UI thread. Returning a boolean in the post call in the authenticate method is not allowed now, because it expects Void.
I am familiar with callbacks in nodejs and trying to grasp this now. Any hints what the best approach would be?
Related
Hello I'm trying to convert a short URL like https://goo.gl/maps/MoaZNS825rpixfKu5 to its original URL https://www.google.com/maps/place/WhirlyBall+Twin+Cities/#44.8508658,-93.2389179,17z/data=!3m1!4b1!4m5!3m4!1s0x87f62f7bd688277b:0xc0ec9f7b1ccd0da8!8m2!3d44.8510743!4d-93.2366811?hl=en-US
I found some solutions in similar old posts but they are not working with Xcode 12.4
I tried using the below code but it didn't return any value when I try to print expandedURL
let shortURL = "https://goo.gl/maps/MoaZNS825rpixfKu5"
func performRequest(urlString: String){
let urlString = shortURL
let url = URL(string: urlString)!
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "HEAD"
URLSession.shared.dataTask(with: urlRequest) { (data, urlResponse, error) in
let expandedURL = urlResponse?.url?.absoluteString
print("expandedURL HEAD: \(expandedURL ?? "Oops, not URL")")
}
.resume()
}
I managed to get it to work with the below code
I know it's somehow a primitive way but it just worked with me :)
let shortURL = //"https://goo.gl/maps/MoaZNS825rpixfKu5"
"https://goo.gl/maps/xNdKp1Q1KqFeWQv99"
performRequest (urlString: shortURL)
func performRequest(urlString: String){
if let url = URL(string: urlString){
let session = URLSession(configuration: .default)
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "HEAD"
let task = session.dataTask(with: urlRequest, completionHandler: handle(data:response:error:))
task.resume()
}
}
func handle (data: Data?, response: URLResponse?, error: Error?){
if error != nil {
print (error)
return
}
if let safeData = data {
let dataString = String(data: safeData, encoding: .utf8)
let expandedURL = response?.url?.absoluteString
print(expandedURL!)
}
}
In my xcode console application (10.12), i m using http post requests for sending data to wcf web service. If that web service works with http there is no any problem. But if i change to secure (https) connection then i can not communicate with web service. I m getting 404 error code.
class request :NSObject,URLSessionDelegate{
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
if let err = error {
print("Error: \(err.localizedDescription)")
} else {
print("Error. Giving up")
}
}
func makeHTTPPostRequest(path: String, params: Dictionary<String,AnyObject>) {
let request = NSMutableURLRequest(url: NSURL(string: path)! as URL)
request.httpMethod = "POST"
do {
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: JSONSerialization.WritingOptions.prettyPrinted)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 10
configuration.timeoutIntervalForResource = 10
let session = URLSession(configuration: configuration,delegate: self, delegateQueue: nil)
let task = session.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
print(response)
})
task.resume()
}
catch{
}
}
And web service code someting like that :
[WebInvoke(UriTemplate = "/Test", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
[OperationContract]
string Test(string name);
I m calling method :
var params = Dictionary<String,AnyObject>()
params["name"] = "Hi" as AnyObject?
var r = request()
r.makeHTTPPostRequest(path:"https://192.168.1.104/sample/Service1.svc/Test",params:params)
This is response from server :
{ status code: 404, headers {
"Cache-Control" = private;
"Content-Length" = 0;
Date = "Sat, 25 Mar 2017 14:59:29 GMT";
Server = "Microsoft-IIS/7.5";
"Set-Cookie" = "ASP.NET_SessionId=l2omo5wflafesmcw2j23sw4t; path=/; HttpOnly";
"X-AspNet-Version" = "4.0.30319";
"X-Powered-By" = "ASP.NET";}
So what i m doing wrong ? Do you have any idea?
Thanks in advance !
I found my mistake, wrong web.config configuration.
The code above works fine.
Best
In using swift 2.2, while using NSURLSession I am not getting the Response. What am I doing wrong?
I have to pass parameters and header in POST request.
func API() {
let userName:String! = "uname"
let password:String! = "password"
let request = NSMutableURLRequest(URL: NSURL(string: URL)!)
request.HTTPMethod = "POST"
let data = try! NSJSONSerialization.dataWithJSONObject(parameter, options:[])
let json = NSString(data: data, encoding: NSUTF8StringEncoding) as! String
request.HTTPBody = json.dataUsingEncoding(NSUTF8StringEncoding)
request.allHTTPHeaderFields = ["key":"value"]
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 = String(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
}
Result is:
responseString = Optional("")
Did you call this service on any REST client like Postman ? if yes and get response so try replace this line
request.allHTTPHeaderFields = ["key":"value"]
with this
request.setValue("value",forHTTPHeaderField:"Key")
and set all values
I am trying to integrate foursquare api in application , logged in successfully and getting authtoken . Now i need to get loggedin user information using authtoken, how to get userinfo(like username and emailId and etc) . Please help me.
You can do so like this:
// Construct url object via string
let url = NSURL(string: "https://api.foursquare.com/v2/users/self?oauth_token=(YOUR_OAUTH_TOKEN)&v=20160207")
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let req = NSURLRequest(URL: url!)
// NSURLSessionDownloadTask is retured from session.dataTaskWithRequest
let task = session.dataTaskWithRequest(req, completionHandler: {
(data, resp, err) in
print(NSString(data: data!, encoding: NSUTF8StringEncoding))
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
if let response = json["response"] as? [String: AnyObject] {
if let user = response["user"] as? [String: AnyObject] {
if let name = user["firstName"] as? String {
// User name
print(name)
}
}
}
} catch {
print("error serializing JSON: \(error)")
}
})
task.resume()
If you use https://github.com/SwiftyJSON/SwiftyJSON, you can deal with JSON data easily.
I am trying to do 2 HTTP requests
in the first request i will get a var that will be used in the second request.
My problem is when I do it using the code below it just runs the second request without running the first.
let url = NSURL(string:"https://loginurl")
let cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
let request = NSMutableURLRequest(URL: url!, cachePolicy: cachePolicy, timeoutInterval: 2.0)
request.HTTPMethod = "POST"
let contentType = " application/x-www-form-urlencoded"
NSURLProtocol.setProperty(contentType, forKey: "Content-Type", inRequest: request)
var dataString = "user details"
var requestBodyData = (dataString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPBody = requestBodyData
NSURLProtocol.setProperty(requestBodyData!.length, forKey: "Content-Length", inRequest: request)
var response: NSURLResponse?
let session = NSURLSession.sharedSession()
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
//code for getting the session id to be used in the second request
})
task.resume()
let url2 = NSURL(string:"http://url2?sessionid")
let request2 = NSMutableURLRequest(URL: url2!, cachePolicy: cachePolicy, timeoutInterval: 2.0)
request2.HTTPMethod = "GET"
dataString=""
requestBodyData = (dataString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
request2.HTTPBody = requestBodyData
NSURLProtocol.setProperty(contentType, forKey: "Content-Type", inRequest: request2)
task = session.dataTaskWithRequest(request2, completionHandler: {data, response, error -> Void in
})
task.resume()
Can anybody explain what can be wrong with this code
Problem 2:
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if let httpRes = response as? NSHTTPURLResponse {
let html = NSString(data:data!, encoding:NSUTF8StringEncoding)
if let match = html?.rangeOfString("(?<=sessionid=')[^\';]+", options: .RegularExpressionSearch) {
portalid = (html?.substringWithRange(match))!
}
}
When I run in simulator it works without issues but when I debug it on iPhone it crashes showing this error "Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFString substringWithRange:]: Range {9223372036854775807, 0} out of bounds; string length 52427'"
Thanks
Here is code sample which makes two requests:
//: Playground - noun: a place where people can play
import UIKit
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
let session = NSURLSession.sharedSession()
session.dataTaskWithURL(NSURL(string: "http://www.google.com")!, completionHandler: { (data :NSData?, response :NSURLResponse?, error :NSError?) -> Void in
let res = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(res!)
// make a new request here
let innerSession = NSURLSession.sharedSession()
innerSession.dataTaskWithURL(NSURL(string: "http://www.google.com")!, completionHandler: { (data :NSData?, response :NSURLResponse?, error :NSError?) -> Void in
let res = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(res!)
}).resume()
}).resume()