-
Notifications
You must be signed in to change notification settings - Fork 0
/
HttpClient+Combine.swift
89 lines (80 loc) · 3.88 KB
/
HttpClient+Combine.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//
// HttpClient+Combine.swift
// HttpKit
//
// Created by Andrei Ermoshin on 4/28/20.
// Copyright © 2020 andreiermoshin. All rights reserved.
//
import Foundation
import Alamofire
#if canImport(Combine)
import Combine
#endif
extension HttpKit.Client {
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public typealias ResponseFuture<T> = Deferred<Future<T, HttpKit.HttpError>>
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
private func cMakeRequest<T: ResponseType>(for endpoint: HttpKit.Endpoint<T, Server>,
withAccessToken accessToken: String?,
responseType: T.Type) -> ResponseFuture<T> {
return Combine.Deferred {
let subject: Future<T, HttpKit.HttpError> = .init { (promise) in
guard let url = endpoint.url(relatedTo: self.server) else {
promise(.failure(.failedConstructUrl))
return
}
var httpRequest = URLRequest(url: url,
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: self.httpTimeout)
httpRequest.httpMethod = endpoint.method.rawValue
httpRequest.allHTTPHeaderFields = endpoint.headers?.dictionary
if let token = accessToken {
let auth: HttpKit.HttpHeader = .authorization(token: token)
httpRequest.setValue(auth.value, forHTTPHeaderField: auth.key)
}
do {
try httpRequest.addParameters(from: endpoint)
} catch let error as HttpKit.HttpError {
promise(.failure(error))
return
} catch {
promise(.failure(.httpFailure(error: error, request: httpRequest)))
return
}
let codes = T.successCodes
let _: DataRequest = AF.request(httpRequest)
.validate(statusCode: codes)
.responseDecodable(of: responseType,
queue: .main,
decoder: JSONDecoder(),
completionHandler: { (response) in
switch response.result {
case .success(let value):
promise(.success(value))
case .failure(let error):
promise(.failure(.httpFailure(error: error, request: httpRequest)))
}
})
// TODO: find a way to react on subscribtion cancellation to cancel http request
}
return subject
}
}
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public func cMakePublicRequest<T: ResponseType>(for endpoint: HttpKit.Endpoint<T, Server>,
responseType: T.Type) -> ResponseFuture<T> {
let future = cMakeRequest(for: endpoint,
withAccessToken: nil,
responseType: responseType)
return future
}
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public func cMakeAuthorizedRequest<T: ResponseType>(for endpoint: HttpKit.Endpoint<T, Server>,
withAccessToken accessToken: String,
responseType: T.Type) -> ResponseFuture<T> {
let future = cMakeRequest(for: endpoint,
withAccessToken: accessToken,
responseType: responseType)
return future
}
}