Swift Alamofire check wait timeout and put error - swift

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...

Related

Correct Alamofire retry for JWT if status 401?

I am trying to make a retry for my Alamofire Interceptor because I work with JSON Web Token. Adapt works great. But the server updates the Access token every 10 minutes after user registration or authorization. After 10 mins Access token doesn't work anymore, and the server response is 401. So I need to Refresh the token when the status is 401. As I mentioned above, adapt works great. But I need help understanding how to deal with retry. Below is my Interceptor:
class RequestInterceptor: Alamofire.RequestInterceptor {
func adapt( _ urlRequest: URLRequest, for session: Session, completion: #escaping (Result<URLRequest, Error>) -> Void) {
var urlRequest = urlRequest
urlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
completion(.success(urlRequest))
}
func retry( _ request: Request, for session: Session, dueTo error: Error, completion: #escaping (RetryResult) -> Void) {
guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 else {
completion(.doNotRetryWithError(error))
return
}
}
}
My View Model:
func refreshTokenFunc() {
AF.request(TabBarModel.Request.refreshTokenUrl, method: .post, parameters: parameters, encoder: JSONParameterEncoder.default, interceptor: RequestInterceptor()).response { response in
...
And usage (I work with SwiftUI):
.task {
tabBarViewModel.refreshTokenFunc()
}
I was trying with some examples from the Internet. But it doesn't work for me.
In you retry you need to call the completion handler on both sides of the guard, not just in the else side. completion(.retry) is common but you could also track a delay to make sure you don't overload the backend.
Additionally, you should be validating response and checking the error, not reaching directly into request.task.
AF.request(...).validate()... // Ensure the response code is within range.
// In retry
guard let error = error.asAFError, error.responseCode == 401 else { ... }

RestAPI response is not same as Postman Response

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

Swift Alamofire "The request timed out" in one of every two requests

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.

Partially downloading data in Swift

I'm trying to develop a download accelerator in Swift. It should get the file's size and divide it to n parts. Then it should download them at once by running multiple threads, and then merge the parts.
I read C# - Creating a Download Accelerator, unfortunately it doesn't help me.
I can do the multiple thread part easily by
DispatchQueue.main.async {
// The new thread
}
but the other part is harder. I usually download a file like this:
try Data(contentsOf: URL(string: assetsUrl!)!)
or I can do the thing that is explained in this answer
class Downloader {
class func load(url: URL, to localUrl: URL, completion: #escaping () -> ()) {
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = try! URLRequest(url: url, method: .get)
let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Success: \(statusCode)")
}
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: localUrl)
completion()
} catch (let writeError) {
print("error writing file \(localUrl) : \(writeError)")
}
} else {
print("Failure: %#", error?.localizedDescription);
}
}
task.resume()
}
}
But this is not C - it's very simplistic and doesn't accept many arguments. How can I make it get "first 200_000 bytes" from the server?
First of all, the server needs to implement HTTP range requests. If it doesn't, and you don't control the server, then you will not be able to do this.
If the server supports HTTP range requests, then you need to specify the range with request headers, as explained here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
The essentials are that you first send a HEAD request to figure out whether the server supports HTTP range requests. This is determined by whether the response includes the Accept-Ranges header, with a non-zero value.
If the server supports HTTP range requests, then you can make a request for the resource, with the Range header set for example to a value of bytes=0-1023 (depends which format the Accept-Ranges header specified, in this case bytes)

Alamofire POST Returning Data

I am using Alamofire to make a post request to server. The post request is working fine.
Issue: When the post request is made, it returns some data which I need. How can I store/ retrieve that data
The POST Request:
Alamofire.request(.POST, postURL, parameters: params)
to get the response closure add
.response { request, response, data, error in }
to the end of your code
ie
Alamofire.request(.POST, "http://httpbin.org/get", parameters: ["foo": "bar"])
.response { request, response, data, error in
print(request)
print(response)
print(data)
print(error)
}
If you are using the latest version of AlamoFire.
If you are using the latest version of AlamoFire.
Try this working fine for me.(Change request arguments based on your need)
let url1 = "http://yoururl.com"
let head = [ "Accept": "application/json;charset=UTF-8",
"Content-Type": "application/json;charset=UTF-8"] // Adding headers
let p = ["Email":"anything","Password": "123"] // Adding parameters if any
Alamofire.request(.POST,url1, parameters: p, encoding : .JSON, headers : head)
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
}