Compare commits

..

No commits in common. "master" and "5.1.0" have entirely different histories.

12 changed files with 73 additions and 138 deletions

View File

@ -1,4 +1,4 @@
// swift-tools-version:5.3
// swift-tools-version:5.0
import PackageDescription
@ -8,16 +8,8 @@ let package = Package(
.macOS(.v10_11),
],
dependencies: [
.package(
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"
)
.package(url: "https://github.com/kylef/PathKit", from: "1.0.0"),
.package(url: "https://github.com/XCEssentials/RepoConfigurator", from: "3.0.0")
],
targets: [
.target(

View File

@ -11,7 +11,7 @@ print("--- BEGIN of '\(Executable.name)' script ---")
// MARK: Parameters
Spec.BuildSettings.swiftVersion.value = "5.3"
Spec.BuildSettings.swiftVersion.value = "5.0"
let localRepo = try Spec.LocalRepo.current()

View File

@ -16,7 +16,8 @@ git:
language: objective-c # fine for Swift as well
osx_image:
- xcode12
- xcode10.2
- xcode11
before_script:
# cd ./.setup && swift run && cd ./.. # RUN this manually!

View File

@ -1,4 +1,4 @@
// swift-tools-version:5.3
// swift-tools-version:5.0
import PackageDescription

View File

@ -1,7 +1,7 @@
[![GitHub License](https://img.shields.io/github/license/XCEssentials/APIClient.svg?longCache=true)](LICENSE)
[![GitHub Tag](https://img.shields.io/github/tag/XCEssentials/APIClient.svg?longCache=true)](https://github.com/XCEssentials/APIClient/tags)
[![Swift Package Manager Compatible](https://img.shields.io/badge/SPM-compatible-brightgreen.svg?longCache=true)](Package.swift)
[![Written in Swift](https://img.shields.io/badge/Swift-5.3-orange.svg?longCache=true)](https://swift.org)
[![Written in Swift](https://img.shields.io/badge/Swift-5.0-orange.svg?longCache=true)](https://swift.org)
[![Supported platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20iOS%20%7C%20tvOS%20%7C%20watchOS%20%7C%20Linux-blue.svg?longCache=true)](Package.swift)
[![Build Status](https://travis-ci.com/XCEssentials/APIClient.svg?branch=master)](https://travis-ci.com/XCEssentials/APIClient)

View File

@ -39,15 +39,20 @@ struct BasicURLRequestFacilitator: URLRequestFacilitator
public
let sharedPrefixURL: URL
public
let onEncodeRequest: OnEncodeRequest
// MARK: - Initializers
public
init(
sharedPrefixURL: URL,
session: URLSession = .shared
session: URLSession = .shared,
onConfigureRequest: @escaping OnEncodeRequest = URLEncoding.default.encode
)
{
self.sharedPrefixURL = sharedPrefixURL
self.session = session
self.onEncodeRequest = onConfigureRequest
}
}

View File

@ -38,10 +38,7 @@ struct RequestEncodingIssue: URLRequestFacilitatorError
public
enum PrepareRequestIssue: URLRequestFacilitatorError
{
case conversionIntoDataFailed(Error)
case conversionDataIntoJSONObjectFailed(Error)
case conversionJSONObjectIntoDictionaryFailed(theObject: Any)
{
case invalidRelativePath(String)
case requestEncodingFailed(RequestEncodingIssue)
}

View File

@ -28,6 +28,11 @@ import Foundation
//---
public
typealias OnEncodeRequest = (URLRequest, Parameters?) -> Result<URLRequest, RequestEncodingIssue>
//---
public
enum HTTPHeaderFieldName: String
{

View File

@ -24,37 +24,48 @@
*/
import Foundation
//---
public
protocol RequestDefinition: Encodable
protocol RequestDefinition
{
static
var relativePath: String { get }
static
var method: HTTPMethod? { get }
static
var parameterEncoding: ParameterEncoding { get }
static
var toDataConverter: (Self) throws -> Data { get }
static
var dataToDictionaryConversionOptions: JSONSerialization.ReadingOptions { get }
}
//---
public
extension RequestDefinition
{
static
var toDataConverter: (Self) throws -> Data { JSONEncoder().encode }
extension RequestDefinition {
/// Parameters for the corresponding URL request.
var parameters: Parameters {
static
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
}
}
}

View File

@ -34,73 +34,18 @@ protocol URLRequestFacilitator
var session: URLSession { get }
var sharedPrefixURL: URL { 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
)
}
}
var onEncodeRequest: OnEncodeRequest { get }
}
// MARK: - Internal methods
public
extension URLRequestFacilitator
{
func prepareRequest(
_ method: HTTPMethod? = nil,
relativePath: String,
parameterEncoding: ParameterEncoding,
parameters: Parameters? = nil
) -> Result<URLRequest, PrepareRequestIssue>
{
@ -119,7 +64,7 @@ extension URLRequestFacilitator
var result = URLRequest(url: targetURL)
result.httpMethod = method?.rawValue
switch parameterEncoding.encode(result, with: parameters)
switch onEncodeRequest(result, parameters)
{
case .success(let output):
return .success(output)
@ -128,4 +73,15 @@ extension URLRequestFacilitator
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
)
}
}

View File

@ -16,24 +16,7 @@ class RequestDefinitionTests: XCTestCase
static
let method: HTTPMethod? = .get
static
let parameterEncoding: ParameterEncoding = URLEncoding.default
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()
}
}
@ -41,26 +24,12 @@ class RequestDefinitionTests: XCTestCase
extension RequestDefinitionTests
{
func test_buildParameters_withoutOptional()
func test_buildParameters()
{
let definition = UserRequestDefinition(id: "123")
let request = try! facilitator.prepareRequest(from: definition).get()
let components = URLComponents(string: request.url!.absoluteString)!
let sut = components.queryItems!
let sut = UserRequestDefinition(id: "123").parameters
XCTAssertEqual(sut.count, 1)
XCTAssertTrue(sut.contains(where: { $0.name == "id" && $0.value == "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" }))
XCTAssertTrue(sut.contains(where: { $0.key == "id" }))
XCTAssertTrue(sut.contains(where: { ($0.value as? String) == "123" }))
}
}

View File

@ -22,7 +22,6 @@ extension URLRequestFacilitatorTests
let sut = facilitator.prepareRequest(
.get,
relativePath: "user",
parameterEncoding: URLEncoding.default,
parameters: ["id": "123"]
)