Compare commits
17 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
89e8d109f3 | |
![]() |
6f014c3ff6 | |
![]() |
f270e16c6f | |
![]() |
aed7af9dd3 | |
![]() |
65a4a05ac0 | |
![]() |
e228e4beb3 | |
![]() |
792c159774 | |
![]() |
7e99ee5a65 | |
![]() |
7f323ec75c | |
![]() |
87fd31b2ea | |
![]() |
79db02c391 | |
![]() |
c72de279d3 | |
![]() |
22e8b5dfe4 | |
![]() |
1b9d653e57 | |
![]() |
bbaff73a60 | |
![]() |
c2245892ce | |
![]() |
b489bbd69b |
|
@ -1,4 +1,4 @@
|
||||||
// swift-tools-version:5.0
|
// swift-tools-version:5.3
|
||||||
|
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
|
@ -8,8 +8,16 @@ let package = Package(
|
||||||
.macOS(.v10_11),
|
.macOS(.v10_11),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://github.com/kylef/PathKit", from: "1.0.0"),
|
.package(
|
||||||
.package(url: "https://github.com/XCEssentials/RepoConfigurator", from: "3.0.0")
|
name: "PathKit",
|
||||||
|
url: "https://github.com/kylef/PathKit",
|
||||||
|
from: "1.0.0"
|
||||||
|
),
|
||||||
|
.package(
|
||||||
|
name: "XCERepoConfigurator",
|
||||||
|
url: "https://github.com/XCEssentials/RepoConfigurator",
|
||||||
|
from: "3.0.0"
|
||||||
|
)
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
|
|
|
@ -11,7 +11,7 @@ print("--- BEGIN of '\(Executable.name)' script ---")
|
||||||
|
|
||||||
// MARK: Parameters
|
// MARK: Parameters
|
||||||
|
|
||||||
Spec.BuildSettings.swiftVersion.value = "5.0"
|
Spec.BuildSettings.swiftVersion.value = "5.3"
|
||||||
|
|
||||||
let localRepo = try Spec.LocalRepo.current()
|
let localRepo = try Spec.LocalRepo.current()
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,7 @@ git:
|
||||||
language: objective-c # fine for Swift as well
|
language: objective-c # fine for Swift as well
|
||||||
|
|
||||||
osx_image:
|
osx_image:
|
||||||
- xcode10.2
|
- xcode12
|
||||||
- xcode11
|
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
# cd ./.setup && swift run && cd ./.. # RUN this manually!
|
# cd ./.setup && swift run && cd ./.. # RUN this manually!
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// swift-tools-version:5.0
|
// swift-tools-version:5.3
|
||||||
|
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://github.com/XCEssentials/APIClient/tags)
|
[](https://github.com/XCEssentials/APIClient/tags)
|
||||||
[](Package.swift)
|
[](Package.swift)
|
||||||
[](https://swift.org)
|
[](https://swift.org)
|
||||||
[](Package.swift)
|
[](Package.swift)
|
||||||
[](https://travis-ci.com/XCEssentials/APIClient)
|
[](https://travis-ci.com/XCEssentials/APIClient)
|
||||||
|
|
||||||
|
|
|
@ -39,20 +39,15 @@ struct BasicURLRequestFacilitator: URLRequestFacilitator
|
||||||
public
|
public
|
||||||
let sharedPrefixURL: URL
|
let sharedPrefixURL: URL
|
||||||
|
|
||||||
public
|
|
||||||
let onEncodeRequest: OnEncodeRequest
|
|
||||||
|
|
||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
|
|
||||||
public
|
public
|
||||||
init(
|
init(
|
||||||
sharedPrefixURL: URL,
|
sharedPrefixURL: URL,
|
||||||
session: URLSession = .shared,
|
session: URLSession = .shared
|
||||||
onConfigureRequest: @escaping OnEncodeRequest = URLEncoding.default.encode
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.sharedPrefixURL = sharedPrefixURL
|
self.sharedPrefixURL = sharedPrefixURL
|
||||||
self.session = session
|
self.session = session
|
||||||
self.onEncodeRequest = onConfigureRequest
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,9 @@ struct RequestEncodingIssue: URLRequestFacilitatorError
|
||||||
public
|
public
|
||||||
enum PrepareRequestIssue: URLRequestFacilitatorError
|
enum PrepareRequestIssue: URLRequestFacilitatorError
|
||||||
{
|
{
|
||||||
|
case conversionIntoDataFailed(Error)
|
||||||
|
case conversionDataIntoJSONObjectFailed(Error)
|
||||||
|
case conversionJSONObjectIntoDictionaryFailed(theObject: Any)
|
||||||
case invalidRelativePath(String)
|
case invalidRelativePath(String)
|
||||||
case requestEncodingFailed(RequestEncodingIssue)
|
case requestEncodingFailed(RequestEncodingIssue)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,11 +28,6 @@ import Foundation
|
||||||
|
|
||||||
//---
|
//---
|
||||||
|
|
||||||
public
|
|
||||||
typealias OnEncodeRequest = (URLRequest, Parameters?) -> Result<URLRequest, RequestEncodingIssue>
|
|
||||||
|
|
||||||
//---
|
|
||||||
|
|
||||||
public
|
public
|
||||||
enum HTTPHeaderFieldName: String
|
enum HTTPHeaderFieldName: String
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,48 +24,37 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
//---
|
||||||
|
|
||||||
public
|
public
|
||||||
protocol RequestDefinition
|
protocol RequestDefinition: Encodable
|
||||||
{
|
{
|
||||||
static
|
static
|
||||||
var relativePath: String { get }
|
var relativePath: String { get }
|
||||||
|
|
||||||
static
|
static
|
||||||
var method: HTTPMethod? { get }
|
var method: HTTPMethod? { get }
|
||||||
|
|
||||||
|
static
|
||||||
|
var parameterEncoding: ParameterEncoding { get }
|
||||||
|
|
||||||
|
static
|
||||||
|
var toDataConverter: (Self) throws -> Data { get }
|
||||||
|
|
||||||
|
static
|
||||||
|
var dataToDictionaryConversionOptions: JSONSerialization.ReadingOptions { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---
|
||||||
|
|
||||||
public
|
public
|
||||||
extension RequestDefinition {
|
extension RequestDefinition
|
||||||
|
{
|
||||||
|
static
|
||||||
|
var toDataConverter: (Self) throws -> Data { JSONEncoder().encode }
|
||||||
|
|
||||||
/// Parameters for the corresponding URL request.
|
static
|
||||||
var parameters: Parameters {
|
var dataToDictionaryConversionOptions: JSONSerialization.ReadingOptions { .init() }
|
||||||
|
|
||||||
Mirror
|
|
||||||
.init(reflecting: self)
|
|
||||||
.children
|
|
||||||
.compactMap{
|
|
||||||
|
|
||||||
(child: (label: String?, value: Any)) -> (key: String, value: Any)? in
|
|
||||||
|
|
||||||
//---
|
|
||||||
|
|
||||||
if
|
|
||||||
let key = child.label
|
|
||||||
{
|
|
||||||
return (key, child.value)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.reduce(into: [:]) {
|
|
||||||
|
|
||||||
result, nextItem in
|
|
||||||
|
|
||||||
//---
|
|
||||||
|
|
||||||
result[nextItem.key] = nextItem.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,18 +34,73 @@ protocol URLRequestFacilitator
|
||||||
var session: URLSession { get }
|
var session: URLSession { get }
|
||||||
|
|
||||||
var sharedPrefixURL: URL { get }
|
var sharedPrefixURL: URL { get }
|
||||||
|
}
|
||||||
|
|
||||||
var onEncodeRequest: OnEncodeRequest { get }
|
// MARK: - Commands - Public
|
||||||
|
|
||||||
|
public
|
||||||
|
extension URLRequestFacilitator
|
||||||
|
{
|
||||||
|
func prepareRequest<R: RequestDefinition>(
|
||||||
|
from definition: R
|
||||||
|
) -> Result<URLRequest, PrepareRequestIssue>
|
||||||
|
{
|
||||||
|
let parametersData: Data
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
parametersData = try R.toDataConverter(definition)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return .failure(.conversionIntoDataFailed(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
//---
|
||||||
|
|
||||||
|
let parametersObject: Any
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
parametersObject = try JSONSerialization
|
||||||
|
.jsonObject(
|
||||||
|
with: parametersData,
|
||||||
|
options: R.dataToDictionaryConversionOptions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return .failure(.conversionDataIntoJSONObjectFailed(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
//---
|
||||||
|
|
||||||
|
guard
|
||||||
|
let parameters = parametersObject as? Parameters
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return .failure(.conversionJSONObjectIntoDictionaryFailed(theObject: parametersObject))
|
||||||
|
}
|
||||||
|
|
||||||
|
//---
|
||||||
|
|
||||||
|
return prepareRequest(
|
||||||
|
R.method,
|
||||||
|
relativePath: R.relativePath,
|
||||||
|
parameterEncoding: R.parameterEncoding,
|
||||||
|
parameters: parameters
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Internal methods
|
// MARK: - Internal methods
|
||||||
|
|
||||||
public
|
|
||||||
extension URLRequestFacilitator
|
extension URLRequestFacilitator
|
||||||
{
|
{
|
||||||
func prepareRequest(
|
func prepareRequest(
|
||||||
_ method: HTTPMethod? = nil,
|
_ method: HTTPMethod? = nil,
|
||||||
relativePath: String,
|
relativePath: String,
|
||||||
|
parameterEncoding: ParameterEncoding,
|
||||||
parameters: Parameters? = nil
|
parameters: Parameters? = nil
|
||||||
) -> Result<URLRequest, PrepareRequestIssue>
|
) -> Result<URLRequest, PrepareRequestIssue>
|
||||||
{
|
{
|
||||||
|
@ -64,7 +119,7 @@ extension URLRequestFacilitator
|
||||||
var result = URLRequest(url: targetURL)
|
var result = URLRequest(url: targetURL)
|
||||||
result.httpMethod = method?.rawValue
|
result.httpMethod = method?.rawValue
|
||||||
|
|
||||||
switch onEncodeRequest(result, parameters)
|
switch parameterEncoding.encode(result, with: parameters)
|
||||||
{
|
{
|
||||||
case .success(let output):
|
case .success(let output):
|
||||||
return .success(output)
|
return .success(output)
|
||||||
|
@ -73,15 +128,4 @@ extension URLRequestFacilitator
|
||||||
return .failure(.requestEncodingFailed(error))
|
return .failure(.requestEncodingFailed(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareRequest(
|
|
||||||
for definition: RequestDefinition
|
|
||||||
) -> Result<URLRequest, PrepareRequestIssue>
|
|
||||||
{
|
|
||||||
prepareRequest(
|
|
||||||
type(of: definition).method,
|
|
||||||
relativePath: type(of: definition).relativePath,
|
|
||||||
parameters: definition.parameters
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,24 @@ class RequestDefinitionTests: XCTestCase
|
||||||
static
|
static
|
||||||
let method: HTTPMethod? = .get
|
let method: HTTPMethod? = .get
|
||||||
|
|
||||||
|
static
|
||||||
|
let parameterEncoding: ParameterEncoding = URLEncoding.default
|
||||||
|
|
||||||
let id: String
|
let id: String
|
||||||
|
|
||||||
|
var optionalFlag: Int? = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var facilitator: URLRequestFacilitator!
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
|
facilitator = BasicURLRequestFacilitator(sharedPrefixURL: .init(string: "host.com")!)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDown() {
|
||||||
|
facilitator = nil
|
||||||
|
super.tearDown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,12 +41,26 @@ class RequestDefinitionTests: XCTestCase
|
||||||
|
|
||||||
extension RequestDefinitionTests
|
extension RequestDefinitionTests
|
||||||
{
|
{
|
||||||
func test_buildParameters()
|
func test_buildParameters_withoutOptional()
|
||||||
{
|
{
|
||||||
let sut = UserRequestDefinition(id: "123").parameters
|
let definition = UserRequestDefinition(id: "123")
|
||||||
|
let request = try! facilitator.prepareRequest(from: definition).get()
|
||||||
|
let components = URLComponents(string: request.url!.absoluteString)!
|
||||||
|
let sut = components.queryItems!
|
||||||
|
|
||||||
XCTAssertEqual(sut.count, 1)
|
XCTAssertEqual(sut.count, 1)
|
||||||
XCTAssertTrue(sut.contains(where: { $0.key == "id" }))
|
XCTAssertTrue(sut.contains(where: { $0.name == "id" && $0.value == "123" }))
|
||||||
XCTAssertTrue(sut.contains(where: { ($0.value as? String) == "123" }))
|
}
|
||||||
|
|
||||||
|
func test_buildParameters_withOptional()
|
||||||
|
{
|
||||||
|
let definition = UserRequestDefinition(id: "123", optionalFlag: 22)
|
||||||
|
let request = try! facilitator.prepareRequest(from: definition).get()
|
||||||
|
let components = URLComponents(string: request.url!.absoluteString)!
|
||||||
|
let sut = components.queryItems!
|
||||||
|
|
||||||
|
XCTAssertEqual(sut.count, 2)
|
||||||
|
XCTAssertTrue(sut.contains(where: { $0.name == "id" && $0.value == "123" }))
|
||||||
|
XCTAssertTrue(sut.contains(where: { $0.name == "optionalFlag" && $0.value == "22" }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ extension URLRequestFacilitatorTests
|
||||||
let sut = facilitator.prepareRequest(
|
let sut = facilitator.prepareRequest(
|
||||||
.get,
|
.get,
|
||||||
relativePath: "user",
|
relativePath: "user",
|
||||||
|
parameterEncoding: URLEncoding.default,
|
||||||
parameters: ["id": "123"]
|
parameters: ["id": "123"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue