how to set timeout in alamofire with DataRequest - swift

let api = request(url, method: .post, parameters:params, headers:nil)
api.responseJSON { (responseData) -> Void in
//code
}
I don't have time to do code refactoring.
So I want to set the timeout based on the code above, how can I do it?

let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 12
configuration.timeoutIntervalForResource = 12
let alamoFireManager = Alamofire.Session.init(configuration: configuration)
alamoFireManager.request(url, method: .post, parameters: params).responseJSON { response in
switch (response.result) {
case .success:
break
case .failure(let error):
print(error)
break
}
}

Related

Alamofire ssl wrong: sessionDeinitialized

I am trying to connect to my https server which use a custom certificate(export on the server .p12 certificate).
Here is my code:
let filePath = Bundle.main.path(forResource: "ch-server", ofType: "cer")
let data = try! Data(contentsOf: URL(fileURLWithPath: filePath!))
let certificate = SecCertificateCreateWithData(nil, data as CFData)!
let pinEvaluator = PinnedCertificatesTrustEvaluator(certificates: [certificate], acceptSelfSignedCertificates: true, performDefaultValidation: true, validateHost: true)
let trustManager = ServerTrustManager(evaluators: [CHConstants.ApiHost: pinEvaluator])
let session = Session(serverTrustManager: trustManager)
session.request(url, method: .post, parameters: ["phone", phone], encoder: JSONParameterEncoder.default, headers: headers).responseJSON { response in
switch response.result {
case .success:
print("data:\(response.data)")
case let .failure(error):
print("error:\(error)")
}
}
// AF.request(url, method: .post, parameters: ["phone", phone], encoder: JSONParameterEncoder.default, headers: headers).responseJSON { response in
// switch response.result {
// case .success:
// print(response.data)
// case let .failure(error):
// print(error)
// }
// }
but the response is error:
error:sessionDeinitialized
You need to keep your Session instance alive. Otherwise it will be immediately deinitialized and your requests cancelled, which is what that error indicates. Most commonly this is done through a singleton or other reference storage pattern.

Alamofire 4 request to open weather

Working on my first Alamofire request and a code that is updated to Alamofire 4 . Can't get this Alamofire.request .responseJSON properly updated. I am looking at the Migration documentation: but not clever enough. Any suggestions how it should look?
let APIKey = "myAPIkey"
func retrieveCurrentWeatherAtLat(lat: CLLocationDegrees, lon: CLLocationDegrees,
block: (_ weatherCondition: WeatherCondition) -> Void) {
let url = "http://api.openweathermap.org/data/2.5/weather?APPID=\(APIKey)"
let params = ["lat": lat, "lon": lon]
// Send the request
Alamofire.request(url, method: .get, parameters: params)
.responseJSON { request, response, result in
switch result {
case .Success(let json):
let json = JSON(json)
block(weatherCondition: self.createWeatherConditionFronJson(json))
case .Failure(_, let error):
print("Error: \(error)")
}
}
}
maybe can help you
Alamofire.request(url, method: .get, parameters: params, encoding: JSONEncoding.default).responseJSON { (response) in
switch response.result {
case .Success(let json):
let json = JSON(json)
block(weatherCondition: self.createWeatherConditionFronJson(json))
case .Failure(_, let error):
print("Error: \(error)")
}
}
let APIKey = "YourApiKeyComesHere"
// Sending the request to Open Weather
func retrieveCurrentWeatherAtLat(lat: CLLocationDegrees, lon: CLLocationDegrees,
block: #escaping (_ weatherCondition: WeatherCondition) -> Void) {
let url = "https://api.openweathermap.org/data/2.5/weather?APPID=\(APIKey)"
let params = ["lat": lat, "lon": lon]
print("Sending request... \(url)")
let request = Alamofire.request(url, method: .get, parameters: params, encoding: URLEncoding(destination: .queryString)).responseJSON { (response) in
print("Got response from server: \(response)")
switch response.result {
case .success(let json):
let json = JSON(json)
block(self.createWeatherConditionFronJson(json: json))
print("Success: \(json)") //test
case .failure(let error):
print("Error: \(error)")
}
}
request.resume()
}

How to make put request parameters with image Alamofire?

I am sending request through this format to make request with parameters. But how will I sent image as multipart body with this parameters?
class APIManager: NSObject {
enum Router: URLRequestConvertible {
static var baseURLString = baseURLString
static let xSource = X_SOURCE_HEADER
case updateProfile([String: AnyObject])
var method: HTTPMethod {
switch self {
case .updateProfile:
return .put
}
}
var path: String {
switch self {
case .updateStockShelfUnits:
return profile_url
}
}
func asURLRequest() throws -> URLRequest {
let url = try GlobalData.gBaseURLString.asURL()
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
urlRequest.httpMethod = method.rawValue
switch self {
case .updateProfile(let parameters):
urlRequest.setValue(access_token, forHTTPHeaderField: "X-User-Token")
urlRequest = try URLEncoding.default.encode(urlRequest, with: parameters)
}
return urlRequest
}
}
func makeRequestToUpdateProfile(param: [String : AnyObject], img: UIImage, completion: #escaping completionHandlerWithSuccessAndErrorMessage) {
Alamofire.request(Router.updateprofile(param)) .responseJSON { response in
switch response.result {
case .success(let JSON):
print(JSON)
completion(true, "Success")
case .failure(let Error):
print("Request failed with error: \(Error)")
completion(false, Error.localizedDescription)
}
}
}
}
Here what I will do to make a request parameters with image as multipart body? Requesting api with only parameters working well.
Upload Photo / File with parameters and custom headers via Swift 3 and Alamofire 4
// import Alamofire
func uploadWithAlamofire() {
let image = UIImage(named: "bodrum")!
// define parameters
let parameters = [
"hometown": "yalikavak",
"living": "istanbul"
]
Alamofire.upload(multipartFormData: { multipartFormData in
if let imageData = UIImageJPEGRepresentation(image, 1) {
multipartFormData.append(imageData, withName: "file", fileName: "file.png", mimeType: "image/png")
}
for (key, value) in parameters {
multipartFormData.append((value?.data(using: .utf8))!, withName: key)
}}, to: "upload_url", method: .post, headers: ["Authorization": "auth_token"],
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.response { [weak self] response in
guard let strongSelf = self else {
return
}
debugPrint(response)
}
case .failure(let encodingError):
print("error:\(encodingError)")
}
})
}
Credit: fatihyildizhan

How to execute alamofire background upload request?

I need to send zip file to server side.
There is my request which I need to work in background
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 10 // seconds
alamoFireManager = Alamofire.SessionManager(configuration: configuration)
appDeligate.log.debug("request was sended")
alamoFireManager.upload(deligate.data!,
to: deligate.url,
method: .post,
headers: headers)
.uploadProgress(closure: {
progress in
print("Upload Progress: \(progress.fractionCompleted)")
})
.validate()
.responseJSON {}
Now it is work properly, but I need to execute this in background. According to the Alamofire README doc
https://github.com/Alamofire/Alamofire
it says
Creating a Session Manager with Background Configuration
let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.app.background")
let sessionManager = Alamofire.SessionManager(configuration: configuration)
I changed my configuration to correspond background configuration
now it looks like this
let configuration = URLSessionConfiguration.background(withIdentifier: "com.room.myApp")
configuration.timeoutIntervalForRequest = 10 // seconds
alamoFireManager = Alamofire.SessionManager(configuration: configuration)
alamoFireManager.upload(deligate.data!,
to: deligate.url,
method: .post,
headers: headers)
.uploadProgress(closure: {
progress in
print("Upload Progress: \(progress.fractionCompleted)")
})
.validate()
.responseJSON {}
And I get error
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Upload tasks from NSData are not supported in background sessions.'
*** First throw call stack:
(0x18ec511b8 0x18d68855c 0x18f33808c 0x18f33796c 0x18f336e68 0x100ef9218 0x100f05dc8 0x18f336dc8 0x18f3378cc 0x100255890 0x1002518e8 0x100234200 0x100234448 0x100ef9218 0x100f05dc8 0x100233fc4 0x100255290 0x10029d238 0x10029ae4c 0x10029ac34 0x10006dd78 0x100071044 0x100082708 0x10002b310 0x100ef9258 0x100ef9218 0x100f0726c 0x100f08e2c 0x100f08b78 0x18dce32a0 0x18dce2d8c)
libc++abi.dylib: terminating with uncaught exception of type NSException
What am I doing wrong?
Is it issue from my side or lib side?
Feel free to ask
Edit
there is sending flow
There is how I create zip file
internal func madeRequest() {
DispatchQueue.global().async {
if self.createZipPhotoDir() {
self.appDeligate.log.debug("zip dir was created")
self.serverConnection.makeServerRequest()
} else {
self.appDeligate.log.error("can NOT execute createZipPhotoDir()")
}
}
}
private func createZipPhotoDir() -> Bool {
let withContentsOfDirectory: String! = UtilDirectory.pathToMyCurrentAvatarDir.tweak() // "/var/mobile/Containers/Data/Application/739A895E-7BCA-47A8-911F-70FBC812CEB3/Documents/default#domein.com/AvatarPackage/name/"
let atPath: String! = UtilDirectory.tempZipPath.tweak() // "/var/mobile/Containers/Data/Application/739A895E-7BCA-47A8-911F-70FBC812CEB3/Documents/default#domein.com/tmpZipDir.zip"
return SSZipArchive.createZipFile(atPath: atPath, withContentsOfDirectory: withContentsOfDirectory)
}
zip file is creating ok
Then I make server request
required init() {
configureAlamofireManager()
}
private func configureAlamofireManager() {
let configuration = URLSessionConfiguration.background(withIdentifier: "com.fittingroom.newtimezone.Fitzz")
alamoFireManager = Alamofire.SessionManager(configuration: configuration)
}
internal func makeServerRequest() {
appDeligate.log.debug("request was sended")
alamoFireManager.upload(deligate.data!,
to: deligate.url,
method: .post,
headers: headers)
.uploadProgress(closure: {
progress in
print("Upload Progress: \(progress.fractionCompleted)")
})
.validate()
.responseJSON {
[weak self]
response in
self?.appDeligate.log.debug("response : \(response)")
self?.appDeligate.log.debug(String(describing: response.timeline))
switch response.result {
case .success(let value):
self?.appDeligate.log.debug("succes in server connection response")
let result = self?.getStatusCodeAndData(json: JSON(value))
self?.deligate.onSuccess(statusCode: result?.statusCode, data: result?.data)
case .failure(let error):
self?.appDeligate.log.error("error in UploadingRequest : \(error)")
self?.deligate.onError()
}
}
}
There is a way how I get data to send
internal var data: Data {
var data = Data()
let filePath = UtilDirectory.tempZipPath.tweak()
if let result = UtilFile.exists(path: filePath), result.isFileExist == true, result.whatIsIt == .file {
if let fileData = FileManager.default.contents(atPath: filePath) {
data = fileData
appDeligate.log.debug("*** DATA : \(data) ***")
} else {
print("Could not parse the file")
}
} else {
appDeligate.log.error("some ERROR here: file not exist")
}
return data
}
from Background Transfer Considerations
:
Only upload tasks from a file are supported (uploading from data objects or a stream will fail after the program exits).
that means it is limitation from NSURLSession - you need you upload from a file and then try to solve the other error with file
Update
appDeligate.log.debug("request was sended")
let tempZipFilePath = UtilDirectory.tempZipPath.tweak()
alamoFireManager.upload(tempZipFilePath,
to: deligate.url,
method: .post,
headers: headers)
did you see this section Open Radars:
Open Radars
The following radars have some effect on the current implementation of Alamofire.
rdar://26870455 - Background URL Session Configurations do not work in the simulator
Use below code once, Its working for me
import Alamofire
var sessionManager: Alamofire.SessionManager
var backgroundSessionManager: Alamofire.SessionManager
self.sessionManager = Alamofire.SessionManager(configuration: URLSessionConfiguration.default)
self.backgroundSessionManager = Alamofire.SessionManager(configuration: URLSessionConfiguration.background(withIdentifier: "com.youApp.identifier.backgroundtransfer"))
backgroundSessionManager.upload(multipartFormData: blockFormData!, usingThreshold: UInt64.init(), to: url, method: .post, headers: APIManager.headers(), encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.uploadProgress {
(progress) in
let p = progress.fractionCompleted * 100
uploadProgress(p)
}
upload.responseJSON { response in
switch(response.result) {
case .success(let JSON):
DispatchQueue.main.async {
print(JSON)
}
case .failure(let error):
DispatchQueue.main.async {
print(error)
}
}
}
case .failure(let error):
DispatchQueue.main.async {
print(error)
}
}
})

Handle timeout with Alamofire

Is it possible to add timeout handler for Alamofire request?
In my project I use Alamofire this way:
init() {
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 30
self.alamofireManager = Alamofire.Manager(configuration: configuration)
}
func requestAuthorizationWithEmail(email:NSString, password:NSString, completion: (result: RequestResult) -> Void) {
self.alamofireManager!.request(.POST, "myURL", parameters:["email": email, "password":password])
.responseJSON { response in
switch response.result {
case .Success(let JSON):
//do json stuff
case .Failure(let error):
print("\n\nAuth request failed with error:\n \(error)")
completion(result: .ConnectionFailed)
}
}
}
EDIT:
request fail message
Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x7fc10b937320 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=url, NSErrorFailingURLKey=url, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}
You can compare error._code and if it is equal to -1001 which is NSURLErrorTimedOut then you know this was a timeout.
let manager = Alamofire.SessionManager.default
manager.session.configuration.timeoutIntervalForRequest = 120
manager.request("yourUrl", method: .post, parameters: ["parameterKey": "value"])
.responseJSON {
response in
switch (response.result) {
case .success: // succes path
case .failure(let error):
if error._code == NSURLErrorTimedOut {
print("Request timeout!")
}
}
}
Swift 3
The accepted answer didn't work for me.
After a lot of research, I did it like this:
let manager = Alamofire.SessionManager.default
manager.session.configuration.timeoutIntervalForRequest = 120
manager.request("yourUrl", method: .post, parameters: ["parameterKey": "value"])
Swift 3, Alamofire 4.5.0
I wanted to set the same timeout for every HTTP call in my project.
The key idea is to declare the Alamofire Session Manager as a global variable. Then to create a URLSessionConfiguration variable, set its timeout in seconds and assign it to the manager.
Every call in the project can use this configured session manager.
In my case the global Alamofire Session Manager variable was set in AppDelegate file (globally) and its configuration was managed in its didFinishLaunchingWithOptions method
AppDelegate.swift
import UIKit
var AFManager = SessionManager()
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 4 // seconds
configuration.timeoutIntervalForResource = 4 //seconds
AFManager = Alamofire.SessionManager(configuration: configuration)
return true
}
...
}
From now the Alamofire request function can be called from any part of the app using the afManager.
For example:
AFManager.request("yourURL", method: .post, parameters: parameters, encoding: JSONEncoding.default).validate().responseJSON { response in
...
}
Swift 3.x
class NetworkHelper {
static let shared = NetworkHelper()
var manager: SessionManager {
let manager = Alamofire.SessionManager.default
manager.session.configuration.timeoutIntervalForRequest = 10
return manager
}
func postJSONData( withParams parameters: Dictionary<String, Any>, toUrl urlString: String, completion: #escaping (_ error: Error,_ responseBody: Dictionary<String, AnyObject>?)->()) {
manager.request(urlString, method: .post, parameters: parameters, encoding: JSONEncoding.default).responseJSON { response in
if let error = response.result.error {
if error._code == NSURLErrorTimedOut {
print("Time out occurs!")
}
}
}
}
}
Swift 5, Alamofire 5
The cleanest way I found, that works with the latest version of Alamofire is the following:
AF.request(url).response { (dataResponse: AFDataResponse<Data?>) in
switch dataResponse.result {
case .success(let data):
// succes path
case .failure(let error):
switch error {
case .sessionTaskFailed(URLError.timedOut):
print("Request timeout!")
default:
print("Other error!")
}
}
}
Swift 3.x
Accepted answer didn't worked for me too.
This work for me!
let url = URL(string: "yourStringUrl")!
var urlRequest = URLRequest(url: url)
urlRequest.timeoutInterval = 5 // or what you want
And after:
Alamofire.request(urlRequest).response(completionHandler: { (response) in
/// code here
}
Swift 4
This my way and timeout feature is workable, meanwhile practices singleton for api class.
reference from here
struct AlamofireManager {
static let shared: SessionManager = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 5
let sessionManager = Alamofire.SessionManager(configuration: configuration, delegate: SessionDelegate(), serverTrustPolicyManager: nil)
return sessionManager
}()
}
class Auth {
static let api = Auth()
private init() {}
func headers() -> HTTPHeaders {
return [
"Accept": "XXX",
"Authorization": "XXX",
"Content-Type": "XXX"
]
}
func querySample() {
AlamofireManager.shared.request("api_post_url", method: .post, parameters: ["parametersKey": "value"], encoding: JSONEncoding.default, headers: headers())
.responseJSON(queue: DispatchQueue.global(), options: []) { (response) in
switch response.result {
case .success(let value):
// do your statement
case .failure(let error):
if error._code == NSURLErrorTimedOut {
// timeout error statement
} else {
// other error statement
}
}
})
}
func queryOtherSample() {
AlamofireManager.shared.request("api_get_url", method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers())
.responseJSON(queue: DispatchQueue.global(), options: []) { (response) in
switch response.result {
case .success(let value):
// do your statement
case .failure(let error):
if error._code == NSURLErrorTimedOut {
// timeout error statement
} else {
// other error statement
}
}
})
}
}
For Swift 3.x / Swift 4.0 / Swift 5.0 users with Alamofire >= 5.0
Used request modifier to increase and decrease the timeout interval.
Alamofire's request creation methods offer the most common parameters for customization but sometimes those just aren't enough. The URLRequests created from the passed values can be modified by using a RequestModifier closure when creating requests. For example, to set the URLRequest's timeoutInterval to 120 seconds, modify the request in the closure.
var manager = Session.default
manager.request(urlString, method: method, parameters: dict, headers: headers, requestModifier: { $0.timeoutInterval = 120 }).validate().responseJSON { response in
OR
RequestModifiers also work with trailing closure syntax.
var manager = Session.default
manager.request("https://httpbin.org/get") { urlRequest in
urlRequest.timeoutInterval = 60
urlRequest.allowsConstrainedNetworkAccess = false
}
.response(...)
You can also check it here
Make extension of SessionManager and write a public static variable like this,
"requestTimeOutInterval" this is a public variable. it has time.
extension SessionManager {
public static let custom: SessionManager = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = requestTimeOutInterval
configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
return SessionManager(configuration: configuration)
}()
}
Swift 5.0, Alamofire 5.4.2
The error code when time out always equal to NSURLErrorTimedOut, so
I try to retrieve Error object from AFError and upcast to NSError.
extension AFError {
var isTimeout: Bool {
if isSessionTaskError,
let error = underlyingError as NSError?,
error.code == NSURLErrorTimedOut //-1001
{
return true
}
return false
}
}
Invoke on response closure.
let request = URLRequest(url: URL(string: "https://httpbin.org/delay/10")!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 2)
AF.request(request).responseString(completionHandler: { response in
switch response.result {
case .success(_):
print("success")
case .failure(let error):
if error.isTimeout {
print("Timeout!")
}
}
})
In Alamofire 5.5 SessionManager has been renamed Session
Here is the documentation link
https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%205.0%20Migration%20Guide.md#breaking-api-changes
Also the example of user
let manager = Alamofire.Session.default
manager.session.configuration.timeoutIntervalForRequest = 15
let headers: HTTPHeaders? = token == nil ? nil : [.authorization(bearerToken: token!),.accept("application/json")]
manager.request(path, method: method, parameters: parameter, headers: headers).responseJSON { (response) in
switch response.result {
case .success:
case .failure:
}
}