I am facing a very strange issue while calling RESTful API. I have a login API, I tested it in Postman and it's working perfectly fine. Here is a screenshot.
But once I call it using Alamofire, I get the response as "status :" 1 and "message" : 'Incorrect Credentials' It's the same email and password that I'm using in postman but still I get this response even though my email and password is correct. I have tested it on multiple email and passwords, and for every user it gives me same error.
Here is my login Function..
public func login(email: String, password: String, success: #escaping (UserData) -> (), failure: errorClosure)
{
let parameters: Parameters = [
"email": "\(email)",
"password": "\(password)"
]
session.request(Config.loginURL, method: .post, parameters: parameters, encoding: JSONEncoding.default).responseJSON
{ response in
switch response.result
{
case .success(_):
let json = response.value
print("JSON: \(json ?? "errr")")
MappingHelper.ModelFromResponse(UserData.self, response: response, success: { (result) in
success(result)
}, failure: failure)
case .failure(let error):
failure?(error)
}
}
}
This is how i'm calling it..
helper.login(email: email, password: password) { (UserData) in
print(UserData)
} failure: { (error) in
print(error)
}
Debugging..
The reason I am using session.request instead of AF.request is because when I use AF.request it throws me a certificate error.
The certificate for this server is invalid. You might be connecting to a server that is pretending to be "DOMAIN NAME" which could put your confidential information at risk.
So to bypass this error I created a session with the help of some answer from SO.
private let session: Session = {
let manager = ServerTrustManager(evaluators: ["******.com": DisabledTrustEvaluator()])
let configuration = URLSessionConfiguration.af.default
return Session(configuration: configuration, serverTrustManager: manager)
}()
I think the error is JSONEncoding.default because you don't want to send a JSON body according to your Postman screenshot. You'll want to use a url-form-encoded as defined here
Related
still struggling with this d*** FB SDK :-/
Basically, I've got an app that is supposed to post content to a FB Page. To achieve that, I login using the FB sdk. Then I request authorisations as follow
LoginManager().logIn(permissions: ["pages_manage_posts", "pages_read_engagement", "pages_show_list"], viewController: controller) { result in
print("res \(result)")
switch result {
case .success:
// the pageId is in data>id
Defaults[\.facebookSwitchOn] = true
GraphRequest.init(graphPath: "me/accounts").start { (connexion, result, error) in
guard let result = result as? [String:Any],
let dataArray = result["data"] as? Array<Any>,
let data = dataArray.first as? [String:Any],
let pageId = data["id"] as? String,
let access = data["access_token"] as? String else { return }
print("\(pageId)")
Defaults[\.facebookPageId] = pageId
Defaults[\.facebookPageAccessToken] = access
}
completion(true)
case .failed(let error):
completion(false)
MessageManager.show(.basic(.custom(title: "Oups".local(), message: error.localizedDescription, buttonTitle: nil, configuration: MessageDisplayConfiguration.alert)), in: controller)
default: ()
}
}
I save the pageId and TokenID to be able to perform a POST request as follow
GraphRequest
.init(graphPath: "\(pageId)/photos",
// parameters: ["source" : image, "caption" : text, "access_token" : token, "published" : false],
parameters: ["caption" : contentDescription, "url" : "https://www.cdiscount.com/pdt2/9/2/8/1/700x700/889698377928/rw/figurine-funko-pop-deluxe-game-of-thrones-daen.jpg", "access_token" : token],
httpMethod: .post)
.start { (connexion, result, error) in
completion(Result.success(true))
}
However, I get a weird error telling that publish_actions has been deprecated.
I logged the request using Charles, and here it is https://ibb.co/89wPgKx.
Now here is the debug from the GraphAPI explorer :
curl -i -X POST \ "https://graph.facebook.com/v7.0/104226051340555/photos?caption=test%20message%20from%20Graph%20API%20for%20photo&url=https%3A%2F%2Fwww.cdiscount.com%2Fpdt2%2F9%2F2%2F8%2F1%2F700x700%2F889698377928%2Frw%2Ffigurine-funko-pop-deluxe-game-of-thrones-daen.jpg&access_token=<access token sanitized>"
Basically, it is the same request excepting the fact that parameters in the explorer are URL parameters and they are encapsulated in a json.
I can't understand why the graph explorer request succeeds while the SDK request fails.
I'm totally stuck :-/
Thanks for your help.
My API includes authorization bearer token and three additional headers. My problem is I'm not sending the bearer token right (Postman return the correct data not my simulator). I see a lot of examples for using the request adapter but can I not use that? Thanks!
The auth is actually in the authorization tab not in the header.
**Updated:
Solved the problem by following the documentation.
HTTP Headers
Here is the Alamofire function with working codes:
func getBetsData(completion: ((Bool) -> ())? = nil) {
guard let token = defaults.string(forKey: "token") else {
return
}
let headers: HTTPHeaders = [
.authorization(bearerToken: token),
.init(name: "bet_type", value: type),
.init(name: "bet_status", value: status),
.init(name: "page", value: String(page))
]
AF.request("https://example.com", headers: headers).responseDecodable(of: Bets.self) { response in
switch response.result {
case .success:
if let data = response.data {
do {
let bets = try JSONDecoder().decode(Bets.self, from: data)
print("message: \(bets.message)")
self.setupTableData()
completion?(true)
} catch {
print("Error: \(error)")
completion?(false)
}
}
case.failure(let error):
print(error)
completion?(false)
}
}
}
You can add the headers directly:
let headers: HTTPHeaders = [.authorization(bearerToken: token)]
Additionally, if you're decoding a Decodable value from the response, you should not use responseJSON, as that decodes the Data using JSONSerialization and then you just parse it again. Instead, you should use responseDecodable.
AF.request(...).responseDecodable(of: Bets.self) { response in
// Use response.
}
That will be much more efficient and will capture errors for you automatically.
As mention by Dilan only token is not enought you will need to Bearer in the same Header parameter.
Here is one of the best method to handle Token Request and Retrier in all the request you send to server in the application
https://www.avanderlee.com/swift/authentication-alamofire-request-adapter/
By this you don't need to handle token manually in all the webservice.
In every one of my two calls to loadHeader with the same URL, I get "The request timed out" error. In first try, the function works and I manage to get and parse the response. In second, I get time out. In third it works and in forth time out again. Is it about my code or about server? I tried waiting before trying again as it might be some security protocol of server but it didn't change anything.
Here is error code:
FAILURE: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."
And here is my code:
func loadHeader(url: String){
let parameters = ["foo": "bar"]
Alamofire.request(url, method: .get, parameters: parameters, encoding: JSONEncoding.default)
.validate { request, response, data in
// Custom evaluation closure now includes data (allows you to parse data to dig out error messages if necessary)
return .success
}
.responseJSON {
response in
let json=response.data
self.jsonToObjectHeader(json: json!)
}
}
func jsonToObjectHeader(json:Data){
do{
databases = try JSONDecoder().decode(responseHeader.self,from: json)
if databases.ordersHeader.count == 0 {
let alert = UIAlertView(title: "empty",message: "empty",delegate: nil,cancelButtonTitle: "OK")
alert.show()
}
else {
for i in 0...databases.ordersHeader.count-1 {
myArray2.append(databases.ordersHeader[i].productName!)
}
}
DispatchQueue.main.async {
self.myTableView.reloadData()
self.myTableView.tableFooterView = UIView()
}
//print(databases.ordersHeader[0].companyAddress)
}catch let jsonErr {
print(jsonErr)
}
}
I've added
let parameters = ["foo": "bar"]
thinking I've to give parameters as it is in the function. Just updated
Alamofire.request(url, method: .get, parameters: parameters, encoding: JSONEncoding.default)
to
Alamofire.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default)
and it solved the issue. Posting this in case of someone experiences something similar.
I use the Alamofire for get data from REST api.
Alamofire.request(.GET, url)
.authenticate(user: user, password: password)
.responseString { response in
if (response.result.error != nil)
{
show_error()
}
}
.response { (request, response, data, error) in ...
I get and put error, if user don't have internet connection. And I want to put error if user wait more than 3 second response after request.
How cat I make it? How use timeout in the Alamofire?
Alamofire.SessionManager.default.session.configuration.timeoutIntervalForRequest = 3000
This applies to all requests. If you only want to set the timeout for one specific request:
let sessionManager = Alamofire.SessionManager.default
sessionManager.configuration.timeoutIntervalForRequest = 3000
sessionManager.request(.GET, url)
.authenticate(user: user, password: password)
.responseString { response in
if (response.result.error != nil)
{
show_error()
}
}
.response { (request, response, data, error) in ...
You can find more about session managers in the README file...
See i don't know if this is an error on soundcloud side or a problem with this lib
https://github.com/OAuthSwift/OAuthSwift
So basically i'm having issues with the authentication side of things with the soundcloud api, so i'm using a webview which is programatically created and attaching this to the same view which works perfectly.
The issue is once i try to authenticate using one of the options from soundcloud either Facebook, Gmail the screen is just blank and it doesn't seem to be authenticating when using the connect with Facebook or gmail the reason why i say it isn't authenticating is because nothing is being logged in the console... and the email screen seems to be stuck as you can see in the image below... There's no callback once the authentication is done and this does work since there is output in the console when i'm testing the data being returned.
func doOAuthSoundCloud(consumerKey: String, consumerSecret: String) {
let oauthswift = OAuth2Swift(
consumerKey: consumerKey,
consumerSecret: consumerSecret,
authorizeUrl: authorizeUrl,
accessTokenUrl: accessToken,
responseType: "code"
)
oauthswift.authorize_url_handler = AuthWebViewController()
let state: String = generateStateWithLength(20) as String
oauthswift.authorizeWithCallbackURL( NSURL(string: "oauthswiftexample://oauth-callback/soundcloud")!, scope: "", state: state, success: {
credential, response, parameters in
self.saveUserData(oauthswift,credential.oauth_token)
}, failure: { error in
print(error.localizedDescription)
})
}
func saveUserData(oauthswift: OAuth2Swift, _ oauthToken: String) {
oauthswift.client.get("https://api.soundcloud.com/me?oauth_token=\(oauthToken)",
success: {
data, response in
//let json = JSON(data: data)
print("Some data")
let dataString = NSString(data: data, encoding: NSUTF8StringEncoding)
let userData = JSON(dataString!)
print(userData)
print("Some response")
print(response)
print("Extra data")
}, failure: { error in
print(error)
})
}