Skip to content

Commit

Permalink
Add session configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
rocxteady committed Feb 28, 2024
1 parent 7fe66be commit bcd65bf
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 64 deletions.
35 changes: 28 additions & 7 deletions Sources/WPSwift/API/WPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,42 @@ import Resting

enum NetworkError: LocalizedError {
case urlMalformed
case api
case api(Error)
case unknown

var errorDescription: String? {
switch self {
case .urlMalformed:
"URL is malformed."
case .api:
"API returned an unexpected response."
case .api(let error):
error.localizedDescription
case .unknown:
"Unknown error."
}
}
}

//extension NetworkError: Equatable {
// static func == (lhs: NetworkError, rhs: NetworkError) -> Bool {
// switch (lhs, rhs) {
// case (.urlMalformed, .urlMalformed):
// return true
// case (.api(let errorLeft), .api(let errorRight)):
// return errorLeft.code == errorRight.code
// case (.unknown, .unknown):
// return true
// default:
// return false
// }
// }
//}

public struct WPClient<RequestModel: Encodable, Response: Decodable> {
private let restClient: RestClient
private let requestConfig: RequestConfiguration

init(_ configuration: WPClientConfiguration) throws {
let clientConfiguration = RestClientConfiguration(sessionConfiguration: configuration.sessionConfiguration, jsonDecoder: .initialize())
restClient = RestClient(configuration: clientConfiguration)
restClient = RestClient.initialize()
switch configuration.parameterType {
case .object(let dictionary):
requestConfig = RequestConfiguration(
Expand All @@ -59,12 +73,19 @@ public struct WPClient<RequestModel: Encodable, Response: Decodable> {
}

func fetch() async throws -> Response {
return try await restClient.fetch(with: requestConfig)
do {
return try await restClient.fetch(with: requestConfig)
} catch {
throw NetworkError.api(error)
}
}
}

extension WPClient {
func fetchPublisher() -> AnyPublisher<Response, Error> {
func fetchPublisher() -> AnyPublisher<Response, NetworkError> {
restClient.publisher(with: requestConfig)
.mapError {
NetworkError.api($0)
}.eraseToAnyPublisher()
}
}
7 changes: 2 additions & 5 deletions Sources/WPSwift/API/WPClientConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@ struct WPClientConfiguration {
case model(Encodable)
}

let sessionConfiguration: URLSessionConfiguration
let endpoint: String
let method: HTTPMethod
let encoding: HTTPEncoding
let headers: [String: String]?
let parameterType: ParameterType?

init(sessionConfiguration: URLSessionConfiguration = .default, endpoint: String, method: HTTPMethod = .get, parameters: [String : Any]?, encoding: HTTPEncoding = .urlEncoded, headers: [String: String]? = nil) {
self.sessionConfiguration = sessionConfiguration
init(endpoint: String, method: HTTPMethod = .get, parameters: [String : Any]?, encoding: HTTPEncoding = .urlEncoded, headers: [String: String]? = nil) {
self.endpoint = endpoint
self.method = method
self.encoding = encoding
Expand All @@ -34,8 +32,7 @@ struct WPClientConfiguration {
self.headers = headers
}

init(sessionConfiguration: URLSessionConfiguration = .default, endpoint: String, method: HTTPMethod = .post, requestModel: Encodable?, encoding: HTTPEncoding = .json, headers: [String: String]? = nil) {
self.sessionConfiguration = sessionConfiguration
init(endpoint: String, method: HTTPMethod = .post, requestModel: Encodable?, encoding: HTTPEncoding = .json, headers: [String: String]? = nil) {
self.endpoint = endpoint
self.method = method
self.encoding = encoding
Expand Down
16 changes: 16 additions & 0 deletions Sources/WPSwift/Extensions/RestClient+Configuration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// RestClient+Configuration.swift
//
//
// Created by Ulaş Sancak on 15.10.2023.
//

import Foundation
import Resting

extension RestClient {
static func initialize() -> RestClient {
.init(configuration: .init(sessionConfiguration: WPSwift.sessionConfiguration, jsonDecoder: .initialize()))
}
}

1 change: 1 addition & 0 deletions Sources/WPSwift/WPSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public struct WPSwift {
}
}
static private var _configuration: WPConfiguration?
static let sessionConfiguration = URLSessionConfiguration.default

static func resetConfiguration() {
_configuration = nil
Expand Down
87 changes: 42 additions & 45 deletions Tests/WPSwiftTests/APITests/APIClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,16 @@ final class APIClientTests: XCTestCase {
let value: Double = .infinity
}

private let configuration = URLSessionConfiguration.default
private var cancellables = Set<AnyCancellable>()

override func setUpWithError() throws {
WPSwift.initialize(route: "https://www.example.com/wp-json", namespace: "wp/v2")
URLProtocol.registerClass(MockedURLProtocol.self)
configuration.protocolClasses = [MockedURLProtocol.self]
WPSwift.sessionConfiguration.protocolClasses = [MockedURLProtocol.self]
}

override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
URLProtocol.unregisterClass(MockedURLProtocol.self)
configuration.protocolClasses = nil
WPSwift.sessionConfiguration.protocolClasses = nil
}

func testURL() throws {
Expand Down Expand Up @@ -60,7 +57,7 @@ final class APIClientTests: XCTestCase {
return (response, exampleData)
}

let networkManager = try WPClient<EmptyModel, Mocked>(.init(sessionConfiguration: configuration, endpoint: WPEndpoint.Posts.posts.path, parameters: nil))
let networkManager = try WPClient<EmptyModel, Mocked>(.init(endpoint: WPEndpoint.Posts.posts.path, parameters: nil))
let response = try await networkManager.fetch()
XCTAssertEqual(response.title, "Title", "Response data does not match the example data.")
}
Expand All @@ -73,7 +70,7 @@ final class APIClientTests: XCTestCase {
return (response, exampleData)
}

let networkManager = try WPClient<EmptyModel, Mocked>(.init(sessionConfiguration: configuration, endpoint: WPEndpoint.Posts.posts.path, parameters: nil))
let networkManager = try WPClient<EmptyModel, Mocked>(.init(endpoint: WPEndpoint.Posts.posts.path, parameters: nil))

let publisher = networkManager.fetchPublisher()

Expand Down Expand Up @@ -106,12 +103,12 @@ final class APIClientTests: XCTestCase {
return (response, exampleData)
}

let networkManager = try WPClient<EmptyModel, Mocked>(.init(sessionConfiguration: configuration, endpoint: WPEndpoint.Posts.posts.path, parameters: nil))
let networkManager = try WPClient<EmptyModel, Mocked>(.init(endpoint: WPEndpoint.Posts.posts.path, parameters: nil))
do {
_ = try await networkManager.fetch()
XCTAssert(false, "API returned with success. It should have return with failure!")
} catch NetworkError.api {
XCTAssertEqual(NetworkError.api.errorDescription, "API returned an unexpected response.", "Network error message does not match.")
} catch NetworkError.api(let error) {
XCTAssertNotNil(error.localizedDescription, "API error description should not be nil!")
} catch {
XCTAssertTrue(false, error.localizedDescription)
}
Expand All @@ -125,7 +122,7 @@ final class APIClientTests: XCTestCase {
return (response, exampleData)
}

let networkManager = try WPClient<EmptyModel, Mocked>(.init(sessionConfiguration: configuration, endpoint: WPEndpoint.Posts.posts.path, parameters: nil))
let networkManager = try WPClient<EmptyModel, Mocked>(.init(endpoint: WPEndpoint.Posts.posts.path, parameters: nil))

let publisher = networkManager.fetchPublisher()

Expand All @@ -136,12 +133,11 @@ final class APIClientTests: XCTestCase {
.sink { completion in
switch completion {
case .failure(let error):
guard let error = error as? NetworkError,
error == .api else {
guard case .api = error else {
XCTAssert(false, error.localizedDescription)
return
}
XCTAssertEqual(NetworkError.api.errorDescription, "API returned an unexpected response.", "Network error message does not match.")
XCTAssertNotNil(error.localizedDescription, "API error description should not be nil!")
expectation.fulfill()
case .finished:
XCTAssert(false, "API returned with success. It should have return with failure!")
Expand All @@ -154,35 +150,36 @@ final class APIClientTests: XCTestCase {
waitForExpectations(timeout: 1)
}

func testCombineWithEncodingFailure() throws {
WPSwift.initialize(route: "http://www.example.com/wp-json", namespace: "wp/v2")
let networkManager = try WPClient<EncodableFailure, Mocked>(.init(sessionConfiguration: configuration, endpoint: WPEndpoint.Posts.posts.path, method: .post, requestModel: EmptyModel()))

let publisher = networkManager.fetchPublisher()

let expectation = self.expectation(description: "api")

publisher
.receive(on: RunLoop.main)
.sink { completion in
switch completion {
case .failure(let error):
guard let error = error as? EncodingError,
case .invalidValue = error else {
XCTAssert(false, error.localizedDescription)
return
}
expectation.fulfill()
case .finished:
XCTAssert(false, "API returned with success. It should have return with failure!")
expectation.fulfill()
break
}
} receiveValue: { _ in }
.store(in: &cancellables)

waitForExpectations(timeout: 1)
}
// func testCombineWithEncodingFailure() throws {
// WPSwift.initialize(route: "http://www.example.com/wp-json", namespace: "wp/v2")
// let networkManager = try WPClient<EncodableFailure, Mocked>(.init(endpoint: WPEndpoint.Posts.posts.path, method: .post, requestModel: EmptyModel()))
//
// let publisher = networkManager.fetchPublisher()
//
// let expectation = self.expectation(description: "api")
//
// publisher
// .receive(on: RunLoop.main)
// .sink { completion in
// switch completion {
// case .failure(let error):
// guard case .api(let apiError) = error,
// let encodingError = apiError as? EncodingError,
// case .invalidValue = encodingError else {
// XCTAssert(false, error.localizedDescription)
// return
// }
// expectation.fulfill()
// case .finished:
// XCTAssert(false, "API returned with success. It should have return with failure!")
// expectation.fulfill()
// break
// }
// } receiveValue: { _ in }
// .store(in: &cancellables)
//
// waitForExpectations(timeout: 1)
// }

// func testHeaders() throws {
// let request = APIRequest<EmptyModel, Post>(endpoint: WPEndpoint.Posts.posts.path, method: .get, headers: ["Custom-Header": "Custom-Value"])
Expand All @@ -193,8 +190,8 @@ final class APIClientTests: XCTestCase {
func testErrorDescriptions() {
let urlMalformed: NetworkError = .urlMalformed
XCTAssertEqual(urlMalformed.errorDescription, "URL is malformed.", "Network Error Description does not matcn.")
let api: NetworkError = .api
XCTAssertEqual(api.errorDescription, "API returned an unexpected response.", "Network Error Description does not matcn.")
let api: NetworkError = .api(NSError(domain: "", code: 0))
XCTAssertNotNil(api.localizedDescription, "API error description should not be nil!")
let unknown: NetworkError = .unknown
XCTAssertEqual(unknown.errorDescription, "Unknown error.", "Network Error Description does not matcn.")
}
Expand Down
10 changes: 3 additions & 7 deletions Tests/WPSwiftTests/RepositoryTests/PostsRepositoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,15 @@ import XCTest

@available(macOS 14.0, *)
final class PostsRepositoryTests: XCTestCase {

private let configuration = URLSessionConfiguration.default


override func setUpWithError() throws {
WPSwift.initialize(route: "https://www.example.com/wp-json", namespace: "wp/v2")
URLProtocol.registerClass(MockedURLProtocol.self)
configuration.protocolClasses = [MockedURLProtocol.self]
WPSwift.sessionConfiguration.protocolClasses = [MockedURLProtocol.self]
}

override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
URLProtocol.unregisterClass(MockedURLProtocol.self)
configuration.protocolClasses = nil
WPSwift.sessionConfiguration.protocolClasses = nil
}

func testGetPosts() async throws {
Expand Down

0 comments on commit bcd65bf

Please sign in to comment.