|
13 | 13 | alt="codebeat badge"> |
14 | 14 | </a> |
15 | 15 | <a href="https://github.com/Flinesoft/HandySwift/releases"> |
16 | | - <img src="https://img.shields.io/badge/Version-0.3.0-blue.svg" |
17 | | - alt="Version: 0.3.0"> |
| 16 | + <img src="https://img.shields.io/badge/Version-0.4.0-blue.svg" |
| 17 | + alt="Version: 0.4.0"> |
18 | 18 | <img src="https://img.shields.io/badge/Swift-5.3-FFAC45.svg" |
19 | 19 | alt="Swift: 5.3"> |
20 | 20 | <img src="https://img.shields.io/badge/Platforms-Apple%20%7C%20Linux-FF69B4.svg" |
@@ -82,7 +82,7 @@ public protocol Endpoint { |
82 | 82 | var headers: [String: String] { get } |
83 | 83 | var subpath: String { get } |
84 | 84 | var method: HttpMethod { get } |
85 | | - var queryParameters: [String: String] { get } |
| 85 | + var queryParameters: [String: QueryParameterValue] { get } |
86 | 86 | } |
87 | 87 | ``` |
88 | 88 |
|
@@ -140,16 +140,16 @@ extension MicrosoftTranslatorEndpoint: Endpoint { |
140 | 140 | } |
141 | 141 | } |
142 | 142 |
|
143 | | - var queryParameters: [String: String] { |
144 | | - var queryParameters: [String: String] = ["api-version": "3.0"] |
| 143 | + var queryParameters: [String: QueryParameterValue] { |
| 144 | + var queryParameters: [String: QueryParameterValue] = ["api-version": "3.0"] |
145 | 145 |
|
146 | 146 | switch self { |
147 | 147 | case .languages: |
148 | 148 | break |
149 | 149 |
|
150 | 150 | case let .translate(_, sourceLanguage, targetLanguages, _): |
151 | | - queryParameters["from"] = sourceLanguage.rawValue |
152 | | - queryParameters["to"] = targetLanguages.map { $0.rawValue }.joined(by: ",") |
| 151 | + queryParameters["from"] = .string(sourceLanguage.rawValue) |
| 152 | + queryParameters["to"] = .array(targetLanguages.map { $0.rawValue }) |
153 | 153 | } |
154 | 154 |
|
155 | 155 | return queryParameters |
@@ -233,6 +233,38 @@ let translationsByLanguage = try provider.performRequestAndWait(on: endpoint, de |
233 | 233 |
|
234 | 234 | There's even useful functional methods defined on the `Result` type like `map()`, `flatMap()` or `mapError()` and `flatMapError()`. See the "Transforming Result" section in [this](https://www.hackingwithswift.com/articles/161/how-to-use-result-in-swift) article for more information. |
235 | 235 |
|
| 236 | +### Combine Support |
| 237 | + |
| 238 | + `performRequest(on:decodeBodyTo:)` or `performRequest()` |
| 239 | + |
| 240 | +If you are using Combine in your project (e.g. because you're using SwiftUI), you might want to replace the calls to `performRequest(on:decodeBodyTo:)` or `performRequest(on:)` with the Combine calls `publisher(on:decodeBodyTo:)` or `publisher(on:)`. This will give you an `AnyPublisher` request stream to subscribe to. In success cases you will receive the decoded typed object, in error cases an `ApiError` object exactly like within the `performRequest` completion closure. But instead of a `Result` type you can use `sink` or `catch` from the Combine framework. |
| 241 | + |
| 242 | +For example, the usage with Combine might look something like this: |
| 243 | + |
| 244 | +```Swift |
| 245 | +var cancellables: Set<AnyCancellable> = [] |
| 246 | + |
| 247 | +provider.publisher(on: endpoint, decodeBodyTo: TranslationsResponse.self) |
| 248 | + .debounce(for: .seconds(0.5), scheduler: DispatchQueue.main) |
| 249 | + .subscribe(on: DispatchQueue.global()) |
| 250 | + .receive(on: DispatchQueue.main) |
| 251 | + .sink( |
| 252 | + receiveCompletion: { _ in } |
| 253 | + receiveValue: { (translationsResponse: TranslationsResponse) in |
| 254 | + // do something with the success response object |
| 255 | + } |
| 256 | + ) |
| 257 | + .catch { apiError in |
| 258 | + switch apiError { |
| 259 | + case let .clientError(statusCode, clientError): |
| 260 | + // show an alert to customer with status code & data from clientError body |
| 261 | + default: |
| 262 | + logger.handleApiError(apiError) |
| 263 | + } |
| 264 | + } |
| 265 | + .store(in: &cancellables) |
| 266 | +``` |
| 267 | + |
236 | 268 | ### Plugins |
237 | 269 |
|
238 | 270 | The initializer of `ApiProvider` accepts an array of `Plugin` objects. You can implement your own plugins or use one of the existing ones in the [Plugins](https://github.com/Flinesoft/Microya/tree/main/Sources/Microya/Plugins) directory. Here's are the callbacks a custom `Plugin` subclass can override: |
@@ -297,7 +329,7 @@ public var headers: [String: String] { |
297 | 329 | ] |
298 | 330 | } |
299 | 331 |
|
300 | | -public var queryParameters: [String: String] { [:] } |
| 332 | +public var queryParameters: [String: QueryParameterValue] { [:] } |
301 | 333 | ``` |
302 | 334 |
|
303 | 335 | So technically, the `Endpoint` type only requires you to specify the following 4 things: |
|
0 commit comments