Skip to content

Commit a1c27ef

Browse files
committed
Removes Session in favour of Domain
1 parent cb7020b commit a1c27ef

3 files changed

Lines changed: 48 additions & 59 deletions

File tree

Sources/Endpoints/Domain.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,33 @@ import Foundation
22

33
/// Represents a domain that can process the associated endpoint's
44
public protocol Domain {
5+
6+
var urlSession: URLSession { get }
7+
8+
func baseUrl<E: Endpoint>(for endpoint: E) async throws -> URL
9+
510
/// A URL that represents the baseURL for this domain
611
///
712
/// A fully defined `URLRequest` that represents this a request for the
813
/// specified `Endpoint`. A default implementation exists so in most
914
/// cases you do not need to implement this.
1015
func urlRequest<E: Endpoint>(for endpoint: E) async throws -> URLRequest
16+
17+
/// Returns the data and associated response returned from an API
18+
/// - Parameter request: The URL request that should request this data
19+
func data(for request: URLRequest) async throws -> (Data, URLResponse)
20+
}
21+
22+
public extension Domain {
23+
func urlRequest<E: Endpoint>(for endpoint: E) async throws -> URLRequest {
24+
try await endpoint.urlRequest(baseUrl: baseUrl(for: endpoint))
25+
}
26+
27+
func data(for request: URLRequest) async throws -> (Data, URLResponse) {
28+
if #available(iOS 15, *) {
29+
return try await urlSession.data(for: request)
30+
} else {
31+
return try await urlSession.backport.data(for: request)
32+
}
33+
}
1134
}

Sources/Endpoints/EndpointService.swift

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,15 @@
11
import Foundation
22

3-
/// Represents a session for an EndpointService
4-
///
5-
/// Typically this wraps the `shared` URLSession instance. However you
6-
/// can provide a custom session (useful in testing) as well.
7-
public protocol EndpointSession {
8-
var urlSession: URLSession { get }
9-
/// Returns the data and associated response returned from an API
10-
/// - Parameter request: The URL request that should request this data
11-
func data(for request: URLRequest) async throws -> (Data, URLResponse)
12-
}
13-
143
/// Represents a service that can perform requests against `domains` and their associated `endpoints`
154
public final class EndpointService {
16-
let session: EndpointSession
5+
// let session: EndpointSession
176
public let domain: Domain
187
private var observers: [ObjectIdentifier: WeakBox] = [:]
198

209
/// Creates a new service with the specified session
2110
/// - Parameter session: The session that will process endpoint requests
22-
public init(domain: Domain, session: EndpointSession? = nil, observers: [EndpointServiceObserver] = [EndpointPrintLogger()]) {
11+
public init(domain: Domain, observers: [EndpointServiceObserver] = [EndpointPrintLogger()]) {
2312
self.domain = domain
24-
self.session = session ?? Session()
2513
observers.forEach { register($0) }
2614
}
2715

@@ -208,7 +196,7 @@ private extension EndpointService {
208196
$0.object?.service(self, willBegin: endpoint)
209197
}
210198

211-
let (data, response) = try await session.data(for: request)
199+
let (data, response) = try await domain.data(for: request)
212200
guard let httpResponse = response as? HTTPURLResponse else {
213201
try throwError(error: EndpointError.unexpectedResponse(response), status: -1, endpoint: endpoint)
214202
}
@@ -265,22 +253,3 @@ public enum EndpointError: LocalizedError {
265253
}
266254
}
267255
}
268-
269-
private final class Session: EndpointSession {
270-
var urlSession: URLSession = {
271-
let config = URLSessionConfiguration.default
272-
config.allowsCellularAccess = true
273-
config.allowsExpensiveNetworkAccess = true
274-
config.allowsConstrainedNetworkAccess = true
275-
config.waitsForConnectivity = false
276-
return URLSession(configuration: config)
277-
}()
278-
279-
func data(for request: URLRequest) async throws -> (Data, URLResponse) {
280-
if #available(iOS 15, *) {
281-
return try await urlSession.data(for: request)
282-
} else {
283-
return try await urlSession.backport.data(for: request)
284-
}
285-
}
286-
}

Tests/EndpointsTests/EndpointsTests.swift

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import XCTest
44
final class EndpointsTests: XCTestCase {
55
func testDataSuccess() async throws {
66
let service = EndpointService(
7-
domain: .mockDomain,
8-
session: MockSession(statusCode: 200)
7+
domain: .mockDomain
98
)
109

1110
let (data, response) = try await service.perform(.mockData)
@@ -15,8 +14,7 @@ final class EndpointsTests: XCTestCase {
1514

1615
func testJSONSuccess() async throws {
1716
let service = EndpointService(
18-
domain: .mockDomain,
19-
session: MockSession(statusCode: 200)
17+
domain: .mockDomain
2018
)
2119

2220
let (_, response) = try await service.perform(.mockJSON(filename: "gist"))
@@ -25,8 +23,7 @@ final class EndpointsTests: XCTestCase {
2523

2624
func testBadStatusCode() async {
2725
let service = EndpointService(
28-
domain: .mockDomain,
29-
session: MockSession(statusCode: 404)
26+
domain: .mockDomain(code: 404)
3027
)
3128

3229
do {
@@ -41,8 +38,7 @@ final class EndpointsTests: XCTestCase {
4138

4239
func testCorruptJSON() async throws {
4340
let service = EndpointService(
44-
domain: .mockDomain,
45-
session: MockSession(statusCode: 200)
41+
domain: .mockDomain
4642
)
4743

4844
do {
@@ -57,8 +53,7 @@ final class EndpointsTests: XCTestCase {
5753

5854
func testMisTypeJSON() async throws {
5955
let service = EndpointService(
60-
domain: .mockDomain,
61-
session: MockSession(statusCode: 200)
56+
domain: .mockDomain
6257
)
6358

6459
do {
@@ -73,8 +68,7 @@ final class EndpointsTests: XCTestCase {
7368

7469
func testPostJSON() async throws {
7570
let service = EndpointService(
76-
domain: .mockDomain,
77-
session: MockSession(statusCode: 200)
71+
domain: .mockDomain
7872
)
7973

8074
let (_, response) = try await service.perform(.mockEncodable)
@@ -83,8 +77,7 @@ final class EndpointsTests: XCTestCase {
8377

8478
func testPostJSONGetJSON() async throws {
8579
let service = EndpointService(
86-
domain: .mockDomain,
87-
session: MockSession(statusCode: 200)
80+
domain: .mockDomain
8881
)
8982

9083
let (result, response) = try await service.perform(.mockCodable)
@@ -159,22 +152,19 @@ extension Endpoint where Self == MockJSONEndpoint {
159152
}
160153

161154
private struct MockDomain: Domain {
162-
func urlRequest<E>(for endpoint: E) async throws -> URLRequest where E: Endpoint {
155+
var statusCode: Int
156+
let urlSession = URLSession(configuration: .ephemeral)
157+
158+
func baseUrl<E>(for endpoint: E) async throws -> URL where E : Endpoint {
163159
guard let url = Bundle.module.url(forResource: endpoint.request.path, withExtension: "json") else {
164160
throw EndpointError.badEndpoint("Mock file missing from bundle: \(endpoint.request)")
165161
}
166-
167-
return URLRequest(url: url)
162+
return url
168163
}
169-
}
170-
171-
extension Domain where Self == MockDomain {
172-
static var mockDomain: Self { .init() }
173-
}
174164

175-
private struct MockSession: EndpointSession {
176-
var urlSession: URLSession = .init(configuration: .ephemeral)
177-
var statusCode: Int = 200
165+
func urlRequest<E>(for endpoint: E) async throws -> URLRequest where E: Endpoint {
166+
try await URLRequest(url: baseUrl(for: endpoint))
167+
}
178168

179169
func data(for request: URLRequest) async throws -> (Data, URLResponse) {
180170
let data = try Data(contentsOf: request.url!)
@@ -187,3 +177,10 @@ private struct MockSession: EndpointSession {
187177
return (data, response)
188178
}
189179
}
180+
181+
extension Domain where Self == MockDomain {
182+
static var mockDomain: Self { .init(statusCode: 200) }
183+
static func mockDomain(code: Int) -> Self {
184+
.init(statusCode: code)
185+
}
186+
}

0 commit comments

Comments
 (0)