Skip to content

Instantly share code, notes, and snippets.

@a-voronov
Last active May 28, 2017 22:42
Show Gist options
  • Save a-voronov/d6368e7df0828e36c4aa157a6792d250 to your computer and use it in GitHub Desktop.
Save a-voronov/d6368e7df0828e36c4aa157a6792d250 to your computer and use it in GitHub Desktop.
Lightweight Networking Abstraction Layer
import Foundation
// MARK: - Commons Level
protocol Cancellable {
func cancel()
}
enum Result<T, E: Error> {
case success(T)
case failure(E)
}
// MARK: - Api Service Level
enum ApiRequestParametersEncoding {
case json
case url
case form
}
enum ApiRequestMethod: String {
case head = "HEAD"
case get = "GET"
case post = "POST"
case put = "PUT"
case delete = "DELETE"
case patch = "PATCH"
}
class ApiRequest {
var url: () -> NSURL
var method: ApiRequestMethod
var params: [String: AnyObject]
var encoding: ApiRequestParametersEncoding
var headers: [String: String]
init(
url: @escaping () -> NSURL,
method: ApiRequestMethod,
encoding: ApiRequestParametersEncoding,
params: [String: AnyObject] = [:],
headers: [String: String] = [:]
) {
self.url = url
self.method = method
self.params = params
self.encoding = encoding
self.headers = headers
}
}
typealias ApiRequestProvider = () -> ApiRequest
struct ApiResponse<T> {
let value: T
let response: HTTPURLResponse?
}
struct ApiResponseError<E: Error>: Error {
let error: E
let response: HTTPURLResponse?
}
typealias ApiResponseCallback = (Result<ApiResponse<NSData?>, ApiResponseError<NSError>>) -> Void
protocol ApiService {
func makeRequest(request: ApiRequestProvider, callback: ApiResponseCallback) -> Cancellable
}
// MARK: - Api Router Level
protocol ApiRouter {
var request: ApiRequestProvider { get }
}
// MARK: - Promise Extension (https://gist.github.com/a-voronov/ad0d62f2f465dcd785016cb95d2f4578)
extension Promise: Cancellable {}
typealias ApiResponsePromise = Promise<ApiResponse<NSData?>, ApiResponseError<NSError>>
extension ApiService {
func makeRequest(request: ApiRequestProvider) -> ApiResponsePromise {
return Promise { (fulfill, reject, onCancel) in
let cancellableRequest = makeRequest(request: request) { result in
switch result {
case let .success(value): fulfill(value)
case let .failure(reason): reject(reason)
}
}
onCancel(cancellableRequest.cancel)
}
}
}
@a-voronov
Copy link
Author

a-voronov commented Dec 5, 2016

ApiService makeRequest implementation only needed and it can be anything, like NSURLSession or Alamofire library.
Validation, parsing and other stuff before giving back data can be wrapped into a nice pipeline if using promises

class GetRepositoriesRequest: ApiRequest {
    // ...
}

class GetIssuesRequest: ApiRequest {
    // ...
}

enum GithubApiRouter: ApiRouter {
    case getRepositories
    case getIssues

    var request: ApiRequestProvider {
        switch self {
        case .getRepositories: return GetRepositoriesRequest()
        case .getIssues: return GetIssuesRequest()
        }
    } 
}

class GithubApiService: ApiService {
    func makeRequest(request: ApiRequestProvider, callback: ApiResponseCallback) -> Cancellable {
        // the only thing to implement is how to make request :)
    }
}

// ---

let githubApiService = GithubApiService()

githubApiService.makeRequest(.getReposetories.request) 
    <^> validateResponseCode 
    <^> parseRepositories 
    >>- saveRepositoriesToDatabase

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment