Skip to content

Instantly share code, notes, and snippets.

@soxjke
Created December 7, 2016 17:16
Show Gist options
  • Select an option

  • Save soxjke/0dfa399be2b6f88dbbd328010ce1948b to your computer and use it in GitHub Desktop.

Select an option

Save soxjke/0dfa399be2b6f88dbbd328010ce1948b to your computer and use it in GitHub Desktop.
extension APIService {
// MARK: - AddressAPI
func addressGetUserAddress() -> Signal<ResponseResult<Address>, NoError> {
let converter:(Signal<ResponseResult<Address>, NoError>, Observer<ResponseResult<Address>, NoError>) = createSignal()
let request = AdreessGetHomeAddressRequest(token: authorizationService.token)
executeRequest(request).observeValues { (response) in
let parsedResponse:ResponseResult<Address> = ResponseResult(response: response, mappingFunction: request.mapper)
converter.1.send(value: parsedResponse)
}
return converter.0
}
func addressGetSelectedAddress() -> Signal<ResponseResult<Address>, NoError> {
let converter:(Signal<ResponseResult<Address>, NoError>, Observer<ResponseResult<Address>, NoError>) = createSignal()
let request = AdreessGetSelectedAddressRequest(token: authorizationService.token)
executeRequest(request).observeValues { (response) in
let parsedResponse:ResponseResult<Address> = ResponseResult(response: response, mappingFunction: request.mapper)
converter.1.send(value: parsedResponse)
}
return converter.0
}
func addressRegisterUserAddress(_ address:Address) -> Signal<ResponseResult<Address>, NoError> {
let converter:(Signal<ResponseResult<Address>, NoError>, Observer<ResponseResult<Address>, NoError>) = createSignal()
let request = AdressRegisterHomeAddress(token: authorizationService.token, address: address)
executeRequest(request).observeValues { (response) in
let parsedResponse:ResponseResult<Address> = ResponseResult(response: response, mappingFunction: request.mapper)
converter.1.send(value: parsedResponse)
}
return converter.0
}
func addressRegisterNewAddress(_ address:Address) -> Signal<ResponseResult<Address>, NoError> {
let converter:(Signal<ResponseResult<Address>, NoError>, Observer<ResponseResult<Address>, NoError>) = createSignal()
let request = AdressRegisterSelectedAddress(token: authorizationService.token, address: address)
executeRequest(request).observeValues { (response) in
let parsedResponse:ResponseResult<Address> = ResponseResult(response: response, mappingFunction: request.mapper)
converter.1.send(value: parsedResponse)
}
return converter.0
}
}
class AdressRegisterSelectedAddress: BaseRequest <Address> {
var address:Address?
override var HTTPMethod: RequestType {
get {
return .POST
}
}
override var endPoint: String {
get {
return "/api/address/selected/register"
}
}
override var bodyParameters:[String:AnyObject]? {
get {
let addressJSON = address?.toJSON()
return addressJSON as [String : AnyObject]?
}
}
// MARK: - LifeCycle
convenience init(token: Token?, address:Address) {
self.init(token: token)
self.address = address
}
// MARK: - Private
override func mapFunction(_ source:AnyObject?) -> Address? {
var data:Address? = nil
if let jsonDic = source as? [String:AnyObject] {
data = Mapper<Address>().map(JSON:jsonDic)
}
return data
}
}
class APIService {
fileprivate static let baseURL:String = ""
fileprivate let requestor:NetModule = NetModule(configuration: NetConfig(cacheSize: 250, pinnedHosts: [""]), baseURL: baseURL)
fileprivate var analyzer:Analyzable?
fileprivate var accessHandler:(()->())?
fileprivate var invalidAccessSignal:(Signal<Bool, NoError>, Observer<Bool, NoError>)?
var authorizationService: AuthentificationService = AuthentificationService(baseURL: baseURL)
// MARK: - LifeCycle
init() { }
convenience init(accessHandler:@escaping (()->()), analyzer:Analyzable? = nil) {
self.init()
self.accessHandler = accessHandler
self.analyzer = analyzer
invalidAccessSignal = createSignal()
let _ = invalidAccessSignal?.0.throttle(3.0, on: QueueScheduler.main).observeValues({ (invalid) in
if invalid == true {
self.accessHandler?()
}
})
}
// MARK: - Public
func executeRequest(_ executingRequest:Requestable) -> Signal<ProcessedResponse, NoError> {
let signalProvider:(Signal<ProcessedResponse, NoError>, Observer<ProcessedResponse, NoError>) = createSignal()
requestor.performRequest(executingRequest).observeValues { [weak self] (processedResponse) in
self?.analyzer?.analyzeResponse(processedResponse)
if processedResponse.needRefresh == true {
let _ = self?.authorizationService.refresh().observeValues({ (token) in
if let tokenString = token?.refreshToken {
if tokenString.characters.count > 0 {
var updatedRequest = executingRequest
updatedRequest.token = token
let _ = self?.requestor.performRequest(updatedRequest).observeValues({ (response) in
signalProvider.1.send(value: processedResponse)
})
}
} else {
self?.invalidAccessSignal?.1.send(value: true)
}
})
} else {
signalProvider.1.send(value: processedResponse)
}
}
return signalProvider.0
}
// MARK: - Servisable
func createSignal<T>() -> (signal:Signal<T, NoError>, signalObserver:Observer<T, NoError>) {
let signal : Signal<T, NoError>
let observer : Observer<T, NoError>
(signal, observer) = Signal<T, NoError>.pipe()
return (signal, observer)
}
}
final class AuthentificationService : Authorizable {
fileprivate var networkModule : NetworkRequestable = NetModule()
fileprivate var refreshSignal : Signal<Token?, NoError>? = nil
// MARK: - LifeCycle
init() { }
convenience init(baseURL:String) {
self.init()
networkModule = NetModule(baseURL: baseURL)
}
// MARK: - Public
func authenticate(_ login: String, password: String) -> Signal<String?, NoError> {
let authRequest = AuthorizationRequest(userName: login, password: password)
return networkModule.performRequest(authRequest).map({ (response) -> String? in
let parsedResponse = ResponseResult<Token>(response: response, mappingFunction: authRequest.mapper)
let object = parsedResponse.convertedResponse?.accessToken
self.storedToken = parsedResponse.convertedResponse
return object
})
}
func refresh() -> Signal<Token?, NoError> {
if refreshSignal == nil {
let signal : Signal<Token?, NoError>
let observer : Observer<Token?, NoError>
(signal, observer) = Signal<Token?, NoError>.pipe()
refreshSignal = signal
let refreshAuthRequest = RefreshTokenRequest(refreshToken: self.refreshToken)
networkModule.performRequest(refreshAuthRequest).observeValues({ (response) in
let parsedResponse = ResponseResult<Token>(response: response, mappingFunction: refreshAuthRequest.mapper)
self.storedToken = parsedResponse.convertedResponse
observer.send(value: parsedResponse.convertedResponse)
self.refreshSignal = nil
})
}
return refreshSignal!
}
}
class BaseRequest <T>: Requestable {
var mapper : ((AnyObject?) -> T?)?
var token:Token?
var HTTPMethod: RequestType {
get {
return .UNKNOWN
}
}
var endPoint: String {
get {
return "/"
}
}
var urlParameters:[String:AnyObject]? {
get {
return nil
}
}
var bodyParameters:[String:AnyObject]? {
get {
return nil
}
}
var headers:[String:String]? {
get {
return nil
}
}
// MARK: - LifeCycle
init() {
mapper = mapFunction
}
required convenience init(token: Token?) {
self.init()
self.token = token
}
// MARK: - Public
func requestWithBaseUrl(_ baseURL:String) -> URLRequest {
var requestPath = endPoint
if let urlParameters = urlParameters {
requestPath = requestPath + urlParameters.requestString()
}
let completePath = String(format: "%@%@", baseURL, requestPath)
guard let cleanPath = completePath.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) else { return URLRequest(url:URL(fileURLWithPath: "\\")) }
if let url = URL(string: cleanPath) {
let request = NSMutableURLRequest(url: url)
request.httpMethod = HTTPMethod.rawValue
if let bodyParameters = bodyParameters {
if let data = Data.jsonDataFromDictionary(bodyParameters) {
request.httpBody = data
}
}
var headers:[String:String] = [:]
if let additionalHeaders = self.headers {
headers = headers + additionalHeaders
}
if let accessToken = token?.accessToken {
headers = headers + ["Authorization": "Bearer " + accessToken]
}
request.allHTTPHeaderFields = headers
return request as URLRequest
}
return URLRequest(url:URL(fileURLWithPath: "\\"))
}
// MARK: - Ovverride
func mapFunction(_ source:AnyObject?) -> T? {
return nil
}
}
final class NetModule : NetworkRequestable {
fileprivate var currentSession: URLSession?
fileprivate var baseURL: String?
fileprivate var sessionDelegate: NetSessionDelegate
// MARK: - LifeCycle
init() { sessionDelegate = NetSessionDelegate(configuration: nil) }
convenience init(configuration:NetworkConfigurable? = nil, baseURL:String) {
self.init()
sessionDelegate = NetSessionDelegate(configuration: configuration)
setup(configuration)
self.baseURL = baseURL
}
// MARK: - Public
func performRequest(_ request: Requestable) -> Signal<ProcessedResponse, NoError> {
let signal = Signal<ProcessedResponse, NoError>( { [weak self] (observer) -> Disposable? in
guard let baseURL = self?.baseURL,
let currentSession = self?.currentSession else {
return nil
}
let urlRequest = request.requestWithBaseUrl(baseURL)
let timeLine = NetTimeLine()
let task = currentSession.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
timeLine.complete()
let response:NetResponse = NetResponse(request:request, responseData: data, response: response, error: error as NSError?, timeline:timeLine)
let proceededResponse = ResponseConverter.convert(response)
DispatchQueue.main.async {
observer.send(value: proceededResponse)
}
})
task.resume()
let disposable = ActionDisposable(action: {
task.cancel()
})
return disposable
})
return signal
}
// MARK: - Private
fileprivate func setup(_ configuration:NetworkConfigurable? = nil) {
if let config = configuration {
currentSession = URLSession(configuration: config.configuration, delegate: sessionDelegate, delegateQueue: OperationQueue())
} else {
let configuration = NetConfig(cacheSize: 250)
currentSession = URLSession(configuration: configuration.configuration, delegate: sessionDelegate, delegateQueue: OperationQueue())
}
}
}
import UIKit
enum RequestType:String {
case UNKNOWN
case POST
case PUT
case DELETE
case GET
}
protocol Requestable {
func requestWithBaseUrl(_ baseURL:String) -> URLRequest
var token:Token? {get set}
var HTTPMethod:RequestType {get}
var endPoint:String {get}
var urlParameters:[String:AnyObject]? {get}
var bodyParameters:[String:AnyObject]? {get}
var headers:[String:String]? {get}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment