Skip to content

Commit a153c85

Browse files
authored
Merge pull request #9 from MFB-Technologies-Inc/cleanup-3.0.0
Cleanup 3.0.0
2 parents 698fc3b + 845ab74 commit a153c85

17 files changed

+1103
-1040
lines changed

README.md

+16-19
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![CI](https://github.com/MFB-Technologies-Inc/NetworkService/actions/workflows/ci.yml/badge.svg)](https://github.com/MFB-Technologies-Inc/NetworkService/actions/workflows/ci.yml)
55
[![codecov](https://codecov.io/gh/MFB-Technologies-Inc/NetworkService/branch/main/graph/badge.svg?token=3LpLfgAhq3)](https://codecov.io/gh/MFB-Technologies-Inc/NetworkService)
66

7-
Reactive wrapper for URLSession using Combine. At its core, the library consist of the `NetworkServiceClient` protocol along with a minimal implementation `NetworkService`.
7+
Async wrapper and dependency injection layer for URLSession. At its core, the library consist of the `NetworkServiceClient` protocol along with a minimal implementation `NetworkService`.
88

99
### TopLevelCodable
1010
A notable convenience the library provides is the `TopLevelCodable` protocol that enables easy encoding and decoding of conforming types. The protocol associates a `TopLevelEncoder` and `TopLevelDecoder` with a given type so that it is used by the library without explicitly passing it as a parameter. Additionally, `TopLevelEncodable` and `TopLevelDecodable` are included.
@@ -23,42 +23,39 @@ let foo = Foo(bar: 0)
2323
```
2424
#### GET
2525
```swift
26-
let publisher: AnyPublisher<Foo, Failuer> = networkService.get(url)
27-
let cancellable = publisher.assertNoFailure().sink { foo in
28-
print(foo.bar)
29-
}
26+
let result: Result<Foo, NetworkService.Failure> = await networkService.get(url)
27+
let foo = try result.get()
28+
print(foo.bar)
3029
```
3130

3231
#### POST
3332
```swift
34-
let publisher: AnyPublisher<Foo, Failuer> = networkService.post(foo, to: url)
35-
let cancellable = publisher.assertNoFailure().sink { foo in
36-
print(foo.bar)
37-
}
33+
let result: Result<Foo, NetworkService.Failure> = await networkService.post(foo, to: url)
34+
let foo = try result.get()
35+
print(foo.bar)
3836
```
3937

4038
#### PUT
4139
```swift
42-
let publisher: AnyPublisher<Foo, Failuer> = networkService.put(foo, to: url)
43-
let cancellable = publisher.assertNoFailure().sink { foo in
44-
print(foo.bar)
45-
}
40+
let result: Result<Foo, NetworkService.Failure> = await networkService.put(foo, to: url)
41+
let foo = try result.get()
42+
print(foo.bar)
4643
```
4744

4845
#### DELETE
4946
```swift
50-
let publisher: AnyPublisher<Foo, Failuer> = networkService.get(url)
51-
let cancellable = publisher.assertNoFailure().sink { _ in }
47+
let result: Result<Foo, NetworkService.Failure> = await networkService.get(url)
48+
let foo = try result.get()
49+
print(foo.bar)
5250
```
5351

5452
#### Start
5553
```swift
5654
var request = URLRequest(url: url)
5755
request.method = .GET
58-
let publisher: AnyPublisher<Foo, Failuer> = networkService.start(request)
59-
let cancellable = publisher.assertNoFailure().sink { foo in
60-
print(foo.bar)
61-
}
56+
let result = await networkService.start(request)
57+
let foo = try result.get()
58+
print(foo.bar)
6259
```
6360
## NetworkServiceTestHelper
6461

Sources/NetworkService/NetworkService.swift

-1
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,4 @@ public final class NetworkService {
2424

2525
// MARK: NetworkService+NetworkServiceClient
2626

27-
@available(swift 5.5)
2827
extension NetworkService: NetworkServiceClient {}

Sources/NetworkService/NetworkServiceClient+Post.swift

+129-127
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
// This source code is licensed under the MIT license found in the
77
// LICENSE file in the root directory of this source tree.
88

9-
import Combine
109
import Foundation
1110

1211
extension NetworkServiceClient {
@@ -25,140 +24,143 @@ extension NetworkServiceClient {
2524
let request = URLRequest.build(url: url, body: body, headers: headers, method: .POST)
2625
return await start(request)
2726
}
27+
}
2828

29-
/// - Parameters:
30-
/// - body: The body of the request as `Encodable`
31-
/// - url: The destination for the request
32-
/// - headers: HTTP headers for the request
33-
/// - encoder: `TopLevelEncoder` for encoding the request body
34-
/// - Returns: Type erased publisher with `Data` output and `NetworkService`'s error domain for failure
35-
public func post<RequestBody, Encoder>(
36-
_ body: RequestBody,
37-
to url: URL,
38-
headers: [HTTPHeader],
39-
encoder: Encoder
40-
) async -> Result<Data, Failure>
41-
where RequestBody: Encodable,
42-
Encoder: TopLevelEncoder,
43-
Encoder.Output == Data
44-
{
45-
do {
46-
let body = try encoder.encode(body)
47-
return await post(body, to: url, headers: headers)
48-
} catch {
49-
return .failure(Failure.unknown(error as NSError))
29+
#if canImport(Combine)
30+
import Combine
31+
extension NetworkServiceClient {
32+
/// - Parameters:
33+
/// - body: The body of the request as `Encodable`
34+
/// - url: The destination for the request
35+
/// - headers: HTTP headers for the request
36+
/// - encoder: `TopLevelEncoder` for encoding the request body
37+
/// - Returns: Type erased publisher with `Data` output and `NetworkService`'s error domain for failure
38+
public func post<RequestBody, Encoder>(
39+
_ body: RequestBody,
40+
to url: URL,
41+
headers: [HTTPHeader],
42+
encoder: Encoder
43+
) async -> Result<Data, Failure>
44+
where RequestBody: Encodable,
45+
Encoder: TopLevelEncoder,
46+
Encoder.Output == Data
47+
{
48+
do {
49+
let body = try encoder.encode(body)
50+
return await post(body, to: url, headers: headers)
51+
} catch {
52+
return .failure(Failure.unknown(error as NSError))
53+
}
5054
}
51-
}
5255

53-
/// - Parameters:
54-
/// - body: The body of the request as `TopLevelEnodable`
55-
/// - url: The destination for the request
56-
/// - headers: HTTP headers for the request
57-
/// - Returns: Type erased publisher with `Data` output and `NetworkService`'s error domain for failure
58-
public func post<RequestBody>(
59-
_ body: RequestBody,
60-
to url: URL,
61-
headers: [HTTPHeader]
62-
) async -> Result<Data, Failure>
63-
where RequestBody: TopLevelEncodable
64-
{
65-
do {
66-
let body = try RequestBody.encoder.encode(body)
67-
return await post(body, to: url, headers: headers)
68-
} catch let urlError as URLError {
69-
return .failure(Failure.urlError(urlError))
70-
} catch {
71-
return .failure(Failure.unknown(error as NSError))
56+
/// - Parameters:
57+
/// - body: The body of the request as `TopLevelEnodable`
58+
/// - url: The destination for the request
59+
/// - headers: HTTP headers for the request
60+
/// - Returns: Type erased publisher with `Data` output and `NetworkService`'s error domain for failure
61+
public func post<RequestBody>(
62+
_ body: RequestBody,
63+
to url: URL,
64+
headers: [HTTPHeader]
65+
) async -> Result<Data, Failure>
66+
where RequestBody: TopLevelEncodable
67+
{
68+
do {
69+
let body = try RequestBody.encoder.encode(body)
70+
return await post(body, to: url, headers: headers)
71+
} catch let urlError as URLError {
72+
return .failure(Failure.urlError(urlError))
73+
} catch {
74+
return .failure(Failure.unknown(error as NSError))
75+
}
7276
}
73-
}
7477

75-
/// Send a post request to a `URL`
76-
/// - Parameters:
77-
/// - body: The body of the request as `Data`
78-
/// - url: The destination for the request
79-
/// - headers: HTTP headers for the request
80-
/// - decoder:`TopLevelDecoder` for decoding the response body
81-
/// - Returns: Type erased publisher with decoded output and `NetworkService`'s error domain for failure
82-
public func post<ResponseBody, Decoder>(
83-
_ body: Data,
84-
to url: URL,
85-
headers: [HTTPHeader] = [],
86-
decoder: Decoder
87-
) async -> Result<ResponseBody, Failure>
88-
where ResponseBody: Decodable, Decoder: TopLevelDecoder, Decoder.Input == Data
89-
{
90-
var request = URLRequest(url: url)
91-
request.httpBody = body
92-
request.method = .POST
93-
headers.forEach { request.addValue($0) }
94-
return await start(request, with: decoder)
95-
}
78+
/// Send a post request to a `URL`
79+
/// - Parameters:
80+
/// - body: The body of the request as `Data`
81+
/// - url: The destination for the request
82+
/// - headers: HTTP headers for the request
83+
/// - decoder:`TopLevelDecoder` for decoding the response body
84+
/// - Returns: Type erased publisher with decoded output and `NetworkService`'s error domain for failure
85+
public func post<ResponseBody, Decoder>(
86+
_ body: Data,
87+
to url: URL,
88+
headers: [HTTPHeader] = [],
89+
decoder: Decoder
90+
) async -> Result<ResponseBody, Failure>
91+
where ResponseBody: Decodable, Decoder: TopLevelDecoder, Decoder.Input == Data
92+
{
93+
var request = URLRequest(url: url)
94+
request.httpBody = body
95+
request.method = .POST
96+
headers.forEach { request.addValue($0) }
97+
return await start(request, with: decoder)
98+
}
9699

97-
/// - Parameters:
98-
/// - body: The body of the request as `Data`
99-
/// - url: The destination for the request
100-
/// - headers: HTTP headers for the request
101-
/// - Returns: Type erased publisher with `TopLevelDecodable` output and `NetworkService`'s error domain for failure
102-
public func post<ResponseBody>(
103-
_ body: Data,
104-
to url: URL,
105-
headers: [HTTPHeader] = []
106-
) async -> Result<ResponseBody, Failure>
107-
where ResponseBody: TopLevelDecodable
108-
{
109-
await post(body, to: url, headers: headers, decoder: ResponseBody.decoder)
110-
}
100+
/// - Parameters:
101+
/// - body: The body of the request as `Data`
102+
/// - url: The destination for the request
103+
/// - headers: HTTP headers for the request
104+
/// - Returns: Type erased publisher with `TopLevelDecodable` output and `NetworkService`'s error domain for
105+
/// failure
106+
public func post<ResponseBody>(
107+
_ body: Data,
108+
to url: URL,
109+
headers: [HTTPHeader] = []
110+
) async -> Result<ResponseBody, Failure>
111+
where ResponseBody: TopLevelDecodable
112+
{
113+
await post(body, to: url, headers: headers, decoder: ResponseBody.decoder)
114+
}
111115

112-
/// Send a post request to a `URL`
113-
/// - Parameters:
114-
/// - body: The body of the request as a `Encodable` conforming type
115-
/// - url: The destination for the request
116-
/// - headers: HTTP headers for the request
117-
/// - encoder:`TopLevelEncoder` for encoding the request body
118-
/// - decoder:`TopLevelDecoder` for decoding the response body
119-
/// - Returns: Type erased publisher with decoded output and `NetworkService`'s error domain for failure
120-
public func post<RequestBody, ResponseBody, Encoder, Decoder>(
121-
_ body: RequestBody,
122-
to url: URL,
123-
headers: [HTTPHeader] = [],
124-
encoder: Encoder,
125-
decoder: Decoder
126-
) async -> Result<ResponseBody, Failure>
127-
where RequestBody: Encodable,
128-
ResponseBody: Decodable,
129-
Encoder: TopLevelEncoder,
130-
Encoder.Output == Data,
131-
Decoder: TopLevelDecoder,
132-
Decoder.Input == Data
133-
{
134-
do {
135-
let body = try encoder.encode(body)
136-
return await post(body, to: url, headers: headers, decoder: decoder)
137-
} catch let urlError as URLError {
138-
return .failure(Failure.urlError(urlError))
139-
} catch {
140-
return .failure(Failure.unknown(error as NSError))
116+
/// Send a post request to a `URL`
117+
/// - Parameters:
118+
/// - body: The body of the request as a `Encodable` conforming type
119+
/// - url: The destination for the request
120+
/// - headers: HTTP headers for the request
121+
/// - encoder:`TopLevelEncoder` for encoding the request body
122+
/// - decoder:`TopLevelDecoder` for decoding the response body
123+
/// - Returns: Type erased publisher with decoded output and `NetworkService`'s error domain for failure
124+
public func post<RequestBody, ResponseBody, Encoder, Decoder>(
125+
_ body: RequestBody,
126+
to url: URL,
127+
headers: [HTTPHeader] = [],
128+
encoder: Encoder,
129+
decoder: Decoder
130+
) async -> Result<ResponseBody, Failure>
131+
where RequestBody: Encodable,
132+
ResponseBody: Decodable,
133+
Encoder: TopLevelEncoder,
134+
Encoder.Output == Data,
135+
Decoder: TopLevelDecoder,
136+
Decoder.Input == Data
137+
{
138+
do {
139+
let body = try encoder.encode(body)
140+
return await post(body, to: url, headers: headers, decoder: decoder)
141+
} catch let urlError as URLError {
142+
return .failure(Failure.urlError(urlError))
143+
} catch {
144+
return .failure(Failure.unknown(error as NSError))
145+
}
141146
}
142-
}
143147

144-
/// Send a post request to a `URL`
145-
/// - Parameters:
146-
/// - body: The body of the request as a `TopLevelEnodable` conforming type
147-
/// - url: The destination for the request
148-
/// - headers: HTTP headers for the request
149-
/// - Returns: Type erased publisher with `TopLevelDecodable` output and `NetworkService`'s error domain for failure
150-
public func post<RequestBody, ResponseBody>(
151-
_ body: RequestBody,
152-
to url: URL,
153-
headers: [HTTPHeader] = []
154-
) async -> Result<ResponseBody, Failure>
155-
where RequestBody: TopLevelEncodable,
156-
ResponseBody: TopLevelDecodable
157-
{
158-
await post(body, to: url, headers: headers, encoder: RequestBody.encoder, decoder: ResponseBody.decoder)
148+
/// Send a post request to a `URL`
149+
/// - Parameters:
150+
/// - body: The body of the request as a `TopLevelEnodable` conforming type
151+
/// - url: The destination for the request
152+
/// - headers: HTTP headers for the request
153+
/// - Returns: Type erased publisher with `TopLevelDecodable` output and `NetworkService`'s error domain for
154+
/// failure
155+
public func post<RequestBody, ResponseBody>(
156+
_ body: RequestBody,
157+
to url: URL,
158+
headers: [HTTPHeader] = []
159+
) async -> Result<ResponseBody, Failure>
160+
where RequestBody: TopLevelEncodable,
161+
ResponseBody: TopLevelDecodable
162+
{
163+
await post(body, to: url, headers: headers, encoder: RequestBody.encoder, decoder: ResponseBody.decoder)
164+
}
159165
}
160-
}
161-
162-
#if canImport(Combine)
163-
extension NetworkServiceClient {}
164166
#endif

0 commit comments

Comments
 (0)