Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // RestServiceManager.swift
- // MSHTTPConnection
- //
- // Created by Alexandra T. Georgieva on 2/18/16.
- // Copyright Β© 2016 Alexandra T. Georgieva. All rights reserved.
- //
- import Foundation
- public typealias ExpectedResultParameters = (isArray: Bool, type: NSObject.Type, jsonKey: String?)
- /**This class makes the requests to the backend API
- Responsibilities:
- * takes care of requests configuration - privacy, timeouts, headers etc
- * takes care of blocking the UI if requested
- * coordinates error handling, caching
- * takes care of parsing the response to Swift objects
- */
- open class RestServiceManager {
- //MARK:- Singleton
- private struct Static {
- static var instance: RestServiceManager? = nil
- }
- private static var initSelf: (()->())?
- private static var __once: () = {
- initSelf?()
- }()
- static public var sharedInstance: RestServiceManager {
- if Static.instance == nil {
- initSelf = {
- Static.instance = self.init()
- }
- }
- _ = RestServiceManager.__once
- return Static.instance!
- }
- ///You probably don't want to use it. Use sharedInstanceInstead
- required public init() {
- }
- open static var configurator: RestServiceManagerConfiguratorProtocol.Type?
- //MARK: - Public functions
- open func basicAuthRequest(username: String,
- password: String,
- relativeURL: String,
- parameters: [String: NSObject]?,
- requestType:RequestType,
- header: HeaderTypeProtocol,
- showActivityIndicator: Bool,
- shouldCacheResult: Bool = false,
- shouldIgnoreCache: Bool = false,
- shouldReceiveUpdates: Bool = false,
- clearCacheNotificationNames: [String]? = nil,
- cancelNotificationNames: [String]? = nil,
- expectedResultType:ExpectedResultParameters? = nil,
- successBlock:GeneralSuccessBlock?,
- errorBlock:GeneralErrorBlock?) -> Requestor?{
- let serializer = header.serializer(forRequest: nil)
- serializer?.setAuthorizationHeaderFieldWithUsername(username, password: password)
- return request(relativeURL: relativeURL, parameters: parameters, requestType: requestType, header: header, showActivityIndicator:showActivityIndicator, shouldCacheResult:shouldCacheResult, shouldIgnoreCache:shouldIgnoreCache, shouldReceiveUpdates: shouldReceiveUpdates, clearCacheNotificationNames: clearCacheNotificationNames,
- cancelNotificationNames: cancelNotificationNames,expectedResultType: expectedResultType, successBlock: { response in
- serializer?.clearAuthorizationHeader()
- successBlock?(response)
- }, errorBlock: { request, error in
- serializer?.clearAuthorizationHeader()
- errorBlock?(request, error)
- })
- }
- /**
- If the HTTP method is `GET`, `HEAD`, or `DELETE`, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of the `parameterEncoding` property, and set as the request body.
- */
- open func request(relativeURL: String,
- parameters: [String: NSObject]?,
- httpBody: String? = nil,
- requestType:RequestType,
- header: HeaderTypeProtocol,
- showActivityIndicator: Bool,
- shouldCacheResult: Bool = false,
- shouldIgnoreCache: Bool = false,
- shouldReceiveUpdates: Bool = false,
- clearCacheNotificationNames: [String]? = nil,
- cancelNotificationNames: [String]? = nil,
- expectedResultType:ExpectedResultParameters? = nil,
- successBlock:GeneralSuccessBlock?,
- errorBlock:GeneralErrorBlock?) -> Requestor?{
- let request = requestPool.getRequest(url: relativeURL, parameters: parameters,type: requestType, header: header)
- if let cancelNotificationNames = cancelNotificationNames {
- request.addCancelNotificationNames(cancelNotificationNames)
- }
- if let clearCacheNotificationNames = clearCacheNotificationNames {
- request.addClearCacheNotificationNames(clearCacheNotificationNames)
- }
- let requestor: Requestor?
- switch request.state {
- case .ready:
- if shouldIgnoreCache {
- fallthrough
- }
- else if let data = cacheManager?.getCache(forRequest: request) {
- successBlock?(data)
- if shouldReceiveUpdates {
- let requestor = configureRequestorWithSuccess(successBlock, error: nil, forRequest: request, shouldReceiveUpdates: shouldReceiveUpdates)
- return requestor
- }
- return nil
- }
- else {
- fallthrough
- }
- case .notRequested, .cancelled, .failed:
- request.state = .downloading
- requestor = configureRequestorWithSuccess(successBlock, error: errorBlock, forRequest: request, shouldReceiveUpdates: shouldReceiveUpdates)
- requestor!.isInProgress = true
- requestor!.shouldShowActivityIndicator = showActivityIndicator
- case .waiting, .downloading:
- let requestor = configureRequestorWithSuccess(successBlock, error: errorBlock, forRequest: request, shouldReceiveUpdates: shouldReceiveUpdates)
- requestor.isInProgress = true
- requestor.shouldShowActivityIndicator = showActivityIndicator
- if !request.isShowingActivityIndicator && requestor.shouldShowActivityIndicator {
- LoadingIndicatorManager.sharedInstance.shouldBlockUI()
- request.isShowingActivityIndicator = true
- }
- return requestor
- }
- if let serializer = header.serializer(forRequest: request), request.state != .waiting {
- sessionManager.requestSerializer = serializer
- }
- else {
- return nil
- }
- if !request.isShowingActivityIndicator && requestor!.shouldShowActivityIndicator {
- LoadingIndicatorManager.sharedInstance.shouldBlockUI()
- request.isShowingActivityIndicator = true
- }
- request.shouldImplementDefaultErrorHandling = true
- request.countsOnDefaultErrorHandling = false
- if requestType == .get {
- request.task = sessionManager.get(relativeURL, parameters: parameters, success: {[weak request, weak self] task, result in
- guard let closureRequest = request else {
- return
- }
- self?.requestSuccessBlock(closureRequest, expectedResultType: expectedResultType, shouldCacheData: shouldCacheResult, shouldIgnoreCache: shouldIgnoreCache, task: task, response: result as AnyObject?)
- }, failure: { [weak request, weak self] task, error in
- guard let closureRequest = request else {
- return
- }
- self?.requestErrorBlock(closureRequest, task: task, error: error as NSError, expectedResultType:expectedResultType, shouldIgnoreCache: shouldIgnoreCache)
- })
- }
- else if requestType == .post {
- if httpBody != nil {
- var error : NSError?
- if let absoluteURL = URL.init(string: relativeURL, relativeTo: self.sessionManager.baseURL)?.absoluteString {
- let urlRequest = self.sessionManager.requestSerializer.request(withMethod: "POST", urlString:absoluteURL , parameters: nil, error: &error)
- if error != nil {
- self.requestErrorBlock(request, task: nil, error: error!, expectedResultType:expectedResultType, shouldIgnoreCache: shouldIgnoreCache)
- }
- else {
- urlRequest.httpBody = httpBody?.data(using: String.Encoding.utf8)
- let dataTask = self.sessionManager.dataTask(with: urlRequest as URLRequest, completionHandler: { [weak request, weak self] urlResponse, response, error in
- guard let closureRequest = request else {
- return
- }
- if error != nil {
- self?.requestErrorBlock(closureRequest, task: closureRequest.task, error: error! as NSError, expectedResultType:expectedResultType, shouldIgnoreCache: shouldIgnoreCache)
- }
- else {
- self?.requestSuccessBlock(closureRequest, expectedResultType: expectedResultType, shouldCacheData: shouldCacheResult, shouldIgnoreCache: shouldIgnoreCache, task: closureRequest.task, response: response as AnyObject?)
- }
- })
- request.task = dataTask;
- dataTask.resume()
- }
- }
- else {
- self.requestErrorBlock(request, task: nil, error: NSError(domain: "RestServiceManager", code: 0, userInfo: nil), expectedResultType:expectedResultType, shouldIgnoreCache: shouldIgnoreCache)
- }
- }
- else {
- request.task = sessionManager.post(relativeURL, parameters: parameters, success: { [weak request, weak self] task, result in
- guard let closureRequest = request else {
- return
- }
- self?.requestSuccessBlock(closureRequest, expectedResultType: expectedResultType, shouldCacheData: shouldCacheResult, shouldIgnoreCache: shouldIgnoreCache, task: task, response: result as AnyObject?)
- }, failure: { [weak request, weak self] task, error in
- guard let closureRequest = request else {
- return
- }
- self?.requestErrorBlock(closureRequest, task: task, error: error as NSError, expectedResultType:expectedResultType, shouldIgnoreCache: shouldIgnoreCache)
- })
- }
- }
- else if requestType == .delete{
- request.task = sessionManager.delete(relativeURL, parameters: parameters, success: { [weak request, weak self] task, result in
- guard let closureRequest = request else {
- return
- }
- self?.requestSuccessBlock(closureRequest, expectedResultType: expectedResultType, shouldCacheData: shouldCacheResult, shouldIgnoreCache: shouldIgnoreCache, task: task, response: result as AnyObject?)
- }, failure:{ [weak request, weak self] task, error in
- guard let closureRequest = request else {
- return
- }
- self?.requestErrorBlock(closureRequest, task: task, error: error as NSError, expectedResultType:expectedResultType, shouldIgnoreCache: shouldIgnoreCache)
- })
- }
- return requestor
- }
- open func requestSuccessBlock(_ request: Request, expectedResultType:ExpectedResultParameters?, shouldCacheData: Bool, shouldIgnoreCache: Bool, task: URLSessionDataTask?, response:AnyObject?){
- //parsing the result
- let result = type(of: self).parseResponse(response, expectedResultType: expectedResultType)
- if result == nil {
- request.state = .failed
- requestFinishedWithError(request, error: errorHandler.errorForParsingProblem, expectedResultType:expectedResultType, shouldIgnoreCache: shouldIgnoreCache)
- return
- }
- if shouldCacheData {
- request.state = .ready
- cacheManager?.setCache(forRequest: request, data: cacheManager?.isUsingRawDataForCache == true ? response : result)
- }
- else {
- request.state = .notRequested
- }
- if request.isShowingActivityIndicator {
- LoadingIndicatorManager.sharedInstance.shouldUnblockUI()
- request.isShowingActivityIndicator = false
- }
- request.performSuccessBlocksWithResponse(result)
- request.task = nil
- }
- open func requestErrorBlock(_ request: Request, task: URLSessionDataTask?, error: NSError, expectedResultType: ExpectedResultParameters?, shouldIgnoreCache: Bool){
- let err: ServerErrorProtocol
- //parsing the result
- if request.state == .cancelled {
- err = errorHandler.errorForCancelation
- }
- else {
- request.state = .failed
- if let response = task?.response as? HTTPURLResponse {
- err = errorHandler.error(forResponse: response, error: error)
- }
- else {
- err = errorHandler.errorForInternetProblem
- }
- }
- requestFinishedWithError(request, error: err, expectedResultType:expectedResultType, shouldIgnoreCache: shouldIgnoreCache)
- }
- open class func parseResponse(_ response:AnyObject?, expectedResultType:ExpectedResultParameters?)-> AnyObject?{
- if let expectedResultType = expectedResultType {
- var result: NSObject?
- if expectedResultType.isArray {
- if let jsonKey = expectedResultType.jsonKey,
- let dict = response as? [String: AnyObject]{
- if let jsonArray = dict[jsonKey] as? [AnyObject]{
- if let mappedArray = JSONMapper.JSONMapWithArray(jsonArray, forClass: expectedResultType.type){
- result = mappedArray as NSObject?
- }
- }
- else {
- return [NSObject]() as AnyObject?
- }
- }
- else if let jsonArray = result as? [AnyObject],
- let mappedArray = JSONMapper.JSONMapWithArray(jsonArray, forClass: expectedResultType.type){
- result = mappedArray as NSObject?
- }
- }
- else {
- if let jsonKey = expectedResultType.jsonKey,
- let dict = response as? [String: AnyObject],
- let jsonDict = dict[jsonKey] as? [String: AnyObject]{
- result = JSONMapper.JSONMapWithDictionary(jsonDict, forClass: expectedResultType.type)
- }
- else if let jsonDict = response as? [String: AnyObject]{
- result = JSONMapper.JSONMapWithDictionary(jsonDict, forClass: expectedResultType.type)
- }
- }
- return result
- }
- return response
- }
- open func requestFinishedWithError(_ request: Request, error: ServerErrorProtocol, expectedResultType: ExpectedResultParameters?, shouldIgnoreCache: Bool){
- if request.isShowingActivityIndicator {
- LoadingIndicatorManager.sharedInstance.shouldUnblockUI()
- request.isShowingActivityIndicator = false
- }
- request.performErrorBlocksWithError(error)
- if request.parameters?.keys.contains("Operation") ?? false{
- if let value = request.parameters?["Operation"]{
- if ["getSmartSharing", "getMbbEligibility"].contains(value as! String) {
- request.task = nil
- return
- }
- }
- }
- if request.shouldImplementDefaultErrorHandling || request.countsOnDefaultErrorHandling {
- errorHandler.sharedInstance.handleError(error)
- }
- request.task = nil
- }
- open func configureRequestorWithSuccess(_ success: GeneralSuccessBlock?, error: GeneralErrorBlock?, forRequest request: Request, shouldReceiveUpdates: Bool) -> Requestor {
- let requestor = Requestor(success: success, error: error)
- requestor.request = request
- requestor.shouldReceiveUpdates = shouldReceiveUpdates
- request.addRequestor(requestor)
- return requestor
- }
- open let sessionManager: AFHTTPSessionManager = {
- let configuration = URLSessionConfiguration.ephemeral
- configuration.timeoutIntervalForRequest = configurator!.timeoutTime
- //For security reasons no cache is allowed
- configuration.urlCache = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: "")
- let sessionManager = AFHTTPSessionManager(baseURL: URL(string: configurator!.baseURL), sessionConfiguration: configuration)
- sessionManager.responseSerializer = AFJSONResponseSerializer()
- sessionManager.requestSerializer = AFJSONRequestSerializer()
- return sessionManager
- }()
- //MARK: - Private
- private let requestPool = configurator!.requestPoolType.sharedInstance
- private let cacheManager = configurator!.cacheManagerType?.sharedInstance
- private let errorHandler = configurator!.errorHandlerClass
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement