Skip to content

Commit 59f89e2

Browse files
Merge branch 'ishkawa:master' into master
2 parents c5c8031 + 1a5e7ae commit 59f89e2

25 files changed

+416
-303
lines changed

.github/workflows/ci.yml

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,40 @@ on:
77

88
jobs:
99
podspec:
10-
runs-on: macos-10.15
10+
runs-on: macos-12
1111
name: CocoaPods Lint
1212
env:
13-
DEVELOPER_DIR: "/Applications/Xcode_12.3.app/Contents/Developer"
13+
DEVELOPER_DIR: "/Applications/Xcode_13.4.1.app/Contents/Developer"
1414
steps:
1515
- uses: actions/checkout@v2
1616
- run: pod lib lint --allow-warnings
1717

1818
xcode:
19-
runs-on: macos-10.15
19+
name: ${{ matrix.xcode }}
20+
runs-on: ${{ matrix.runsOn }}
21+
env:
22+
DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
2023
strategy:
21-
matrix:
22-
xcode: [10.3, 11.7, 12.3]
2324
fail-fast: false
24-
name: Xcode ${{ matrix.xcode }}
25-
env:
26-
DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer"
25+
matrix:
26+
include:
27+
- xcode: "Xcode_14.0.1"
28+
runsOn: macOS-12
29+
name: "macOS 12, Xcode 14.0.1, Swift 5.7"
30+
- xcode: "Xcode_13.4.1"
31+
runsOn: macOS-12
32+
name: "macOS 12, Xcode 13.4.1, Swift 5.6.1"
33+
- xcode: "Xcode_12.5.1"
34+
runsOn: macOS-11
35+
name: "macOS 11, Xcode 12.5.1, Swift 5.4.2"
36+
- xcode: "Xcode_12"
37+
runsOn: macOS-10.15
38+
name: "macOS 10.15, Xcode 12.0.1, Swift 5.3"
2739
steps:
2840
- uses: actions/checkout@v2
2941
with:
3042
fetch-depth: 2
31-
- name: test
43+
- name: ${{ matrix.name }}
3244
run: |
3345
set -o pipefail
3446
xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit | xcpretty -c
@@ -39,17 +51,31 @@ jobs:
3951
if: ${{ success() }}
4052

4153
swiftpm:
42-
runs-on: macos-10.15
54+
name: SPM with ${{ matrix.xcode }}
55+
runs-on: ${{ matrix.runsOn }}
56+
env:
57+
DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
4358
strategy:
44-
matrix:
45-
xcode: [11.7, 12.3]
4659
fail-fast: false
47-
name: SwiftPM (Xcode ${{ matrix.xcode }})
48-
env:
49-
DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer"
60+
matrix:
61+
include:
62+
- xcode: "Xcode_14.0.1"
63+
runsOn: macOS-12
64+
name: "macOS 12, Xcode 14.0.1, Swift 5.7"
65+
action: swift test -c debug
66+
- xcode: "Xcode_13.4.1"
67+
runsOn: macOS-12
68+
name: "macOS 12, Xcode 13.4.1, Swift 5.6.1"
69+
action: swift test -c debug
70+
- xcode: "Xcode_12.5.1"
71+
runsOn: macOS-11
72+
name: "macOS 11, Xcode 12.5.1, Swift 5.4.2"
73+
action: swift test -c debug
74+
- xcode: "Xcode_12"
75+
runsOn: macOS-10.15
76+
name: "macOS 10.15, Xcode 12.0.1, Swift 5.3"
77+
action: swift build -c debug
5078
steps:
5179
- uses: actions/checkout@v2
52-
- name: build and test
53-
run: |
54-
swift build
55-
swift test
80+
- name: ${{ matrix.name }}
81+
run: ${{ matrix.action }}

.swift-version

Lines changed: 0 additions & 1 deletion
This file was deleted.

APIKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "APIKit"
3-
s.version = "5.3.0"
3+
s.version = "5.4.0"
44
s.summary = "Type-safe networking abstraction layer that associates request type with response type."
55
s.homepage = "https://github.com/ishkawa/APIKit"
66

APIKit.xcodeproj/project.pbxproj

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
7F698E5A1D9D680C00F1561D /* URLSessionAdapterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E481D9D680C00F1561D /* URLSessionAdapterTests.swift */; };
2222
7F698E5B1D9D680C00F1561D /* SessionCallbackQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E491D9D680C00F1561D /* SessionCallbackQueueTests.swift */; };
2323
7F698E5C1D9D680C00F1561D /* SessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E4A1D9D680C00F1561D /* SessionTests.swift */; };
24-
7F698E5D1D9D680C00F1561D /* test.json in Resources */ = {isa = PBXBuildFile; fileRef = 7F698E4B1D9D680C00F1561D /* test.json */; };
2524
7F698E5E1D9D680C00F1561D /* TestRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E4D1D9D680C00F1561D /* TestRequest.swift */; };
2625
7F698E5F1D9D680C00F1561D /* TestSessionAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E4E1D9D680C00F1561D /* TestSessionAdapter.swift */; };
2726
7F698E601D9D680C00F1561D /* TestSessionTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E4F1D9D680C00F1561D /* TestSessionTask.swift */; };
@@ -48,6 +47,9 @@
4847
7F7048F11D9D8A12003C99F6 /* SessionTaskError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F7048EE1D9D8A12003C99F6 /* SessionTaskError.swift */; };
4948
7F7048F31D9D8A1F003C99F6 /* URLEncodedSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */; };
5049
7FA1690D1D9D8C80006C982B /* HTTPStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FA1690C1D9D8C80006C982B /* HTTPStub.swift */; };
50+
C5725F4B28D8C36500810D7C /* Concurrency.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5725F4A28D8C36500810D7C /* Concurrency.swift */; };
51+
C5B144D828D8D7DC00E30ECD /* ConcurrencyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5B144D728D8D7DC00E30ECD /* ConcurrencyTests.swift */; };
52+
C5FF1DC128A80FFD0059573D /* test.json in Resources */ = {isa = PBXBuildFile; fileRef = C5FF1DC028A80FFD0059573D /* test.json */; };
5153
ECA831481DE4DDBF004EB1B5 /* ProtobufDataParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */; };
5254
ECA8314A1DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA831491DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift */; };
5355
ECA8314C1DE4E677004EB1B5 /* ProtobufBodyParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA8314B1DE4E677004EB1B5 /* ProtobufBodyParameters.swift */; };
@@ -100,7 +102,6 @@
100102
7F698E481D9D680C00F1561D /* URLSessionAdapterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionAdapterTests.swift; sourceTree = "<group>"; };
101103
7F698E491D9D680C00F1561D /* SessionCallbackQueueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionCallbackQueueTests.swift; sourceTree = "<group>"; };
102104
7F698E4A1D9D680C00F1561D /* SessionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionTests.swift; sourceTree = "<group>"; };
103-
7F698E4B1D9D680C00F1561D /* test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = test.json; sourceTree = "<group>"; };
104105
7F698E4D1D9D680C00F1561D /* TestRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestRequest.swift; sourceTree = "<group>"; };
105106
7F698E4E1D9D680C00F1561D /* TestSessionAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSessionAdapter.swift; sourceTree = "<group>"; };
106107
7F698E4F1D9D680C00F1561D /* TestSessionTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSessionTask.swift; sourceTree = "<group>"; };
@@ -129,6 +130,9 @@
129130
7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = URLEncodedSerialization.swift; path = Sources/APIKit/Serializations/URLEncodedSerialization.swift; sourceTree = SOURCE_ROOT; };
130131
7F8ECDFD1B6A799E00234E04 /* Demo.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Demo.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
131132
7FA1690C1D9D8C80006C982B /* HTTPStub.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPStub.swift; sourceTree = "<group>"; };
133+
C5725F4A28D8C36500810D7C /* Concurrency.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Concurrency.swift; sourceTree = "<group>"; };
134+
C5B144D728D8D7DC00E30ECD /* ConcurrencyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrencyTests.swift; sourceTree = "<group>"; };
135+
C5FF1DC028A80FFD0059573D /* test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = test.json; sourceTree = "<group>"; };
132136
ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProtobufDataParser.swift; path = Sources/APIKit/DataParser/ProtobufDataParser.swift; sourceTree = SOURCE_ROOT; };
133137
ECA831491DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProtobufDataParserTests.swift; sourceTree = "<group>"; };
134138
ECA8314B1DE4E677004EB1B5 /* ProtobufBodyParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProtobufBodyParameters.swift; path = Sources/APIKit/BodyParameters/ProtobufBodyParameters.swift; sourceTree = SOURCE_ROOT; };
@@ -201,17 +205,17 @@
201205
ECA8314B1DE4E677004EB1B5 /* ProtobufBodyParameters.swift */,
202206
7F7048D81D9D89FB003C99F6 /* AbstractInputStream.m */,
203207
);
204-
path = APIKit/BodyParameters;
205208
name = BodyParameters;
209+
path = APIKit/BodyParameters;
206210
sourceTree = "<group>";
207211
};
208212
7F18BD161C9730ED003A31DF /* Serializations */ = {
209213
isa = PBXGroup;
210214
children = (
211215
7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */,
212216
);
213-
path = APIKit/Serializations;
214217
name = Serializations;
218+
path = APIKit/Serializations;
215219
sourceTree = "<group>";
216220
};
217221
7F45FCD31A94D02C006863BB = {
@@ -240,11 +244,13 @@
240244
7F698E451D9D680C00F1561D /* RequestTests.swift */,
241245
7F698E491D9D680C00F1561D /* SessionCallbackQueueTests.swift */,
242246
7F698E4A1D9D680C00F1561D /* SessionTests.swift */,
247+
C5B144D628D8D7D000E30ECD /* Concurrency */,
243248
0973EE33259E2DD000879BA2 /* Combine */,
244249
7F698E3B1D9D680C00F1561D /* BodyParametersType */,
245250
7F698E401D9D680C00F1561D /* DataParserType */,
246251
7F698E461D9D680C00F1561D /* SessionAdapterType */,
247252
7F698E4C1D9D680C00F1561D /* TestComponents */,
253+
C5FF1DBF28A80FFD0059573D /* Resources */,
248254
7F698E611D9D681500F1561D /* Supporting Files */,
249255
);
250256
path = APIKitTests;
@@ -297,7 +303,6 @@
297303
isa = PBXGroup;
298304
children = (
299305
7F698E441D9D680C00F1561D /* Info.plist */,
300-
7F698E4B1D9D680C00F1561D /* test.json */,
301306
);
302307
name = "Supporting Files";
303308
sourceTree = "<group>";
@@ -310,6 +315,7 @@
310315
7F7048CA1D9D89BE003C99F6 /* Request.swift */,
311316
7F7048CB1D9D89BE003C99F6 /* Session.swift */,
312317
7F7048CC1D9D89BE003C99F6 /* Unavailable.swift */,
318+
C5725F4928D8C36500810D7C /* Concurrency */,
313319
0969AE0D259DEC3C00C498AF /* Combine */,
314320
7F85FB8B1C9D317300CEE132 /* SessionAdapter */,
315321
7F18BD0D1C972C38003A31DF /* BodyParameters */,
@@ -336,8 +342,8 @@
336342
7F7048D41D9D89F2003C99F6 /* SessionAdapter.swift */,
337343
7F7048D51D9D89F2003C99F6 /* URLSessionAdapter.swift */,
338344
);
339-
path = APIKit/SessionAdapter;
340345
name = SessionAdapter;
346+
path = APIKit/SessionAdapter;
341347
sourceTree = "<group>";
342348
};
343349
7FA19A3D1C9CBF2A005D25AE /* Error */ = {
@@ -347,8 +353,8 @@
347353
7F7048EC1D9D8A12003C99F6 /* RequestError.swift */,
348354
7F7048ED1D9D8A12003C99F6 /* ResponseError.swift */,
349355
);
350-
path = APIKit/Error;
351356
name = Error;
357+
path = APIKit/Error;
352358
sourceTree = "<group>";
353359
};
354360
7FA19A441C9CC9A2005D25AE /* DataParser */ = {
@@ -360,8 +366,33 @@
360366
ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */,
361367
7F7048E71D9D8A08003C99F6 /* StringDataParser.swift */,
362368
);
363-
path = APIKit/DataParser;
364369
name = DataParser;
370+
path = APIKit/DataParser;
371+
sourceTree = "<group>";
372+
};
373+
C5725F4928D8C36500810D7C /* Concurrency */ = {
374+
isa = PBXGroup;
375+
children = (
376+
C5725F4A28D8C36500810D7C /* Concurrency.swift */,
377+
);
378+
name = Concurrency;
379+
path = APIKit/Concurrency;
380+
sourceTree = "<group>";
381+
};
382+
C5B144D628D8D7D000E30ECD /* Concurrency */ = {
383+
isa = PBXGroup;
384+
children = (
385+
C5B144D728D8D7DC00E30ECD /* ConcurrencyTests.swift */,
386+
);
387+
path = Concurrency;
388+
sourceTree = "<group>";
389+
};
390+
C5FF1DBF28A80FFD0059573D /* Resources */ = {
391+
isa = PBXGroup;
392+
children = (
393+
C5FF1DC028A80FFD0059573D /* test.json */,
394+
);
395+
path = Resources;
365396
sourceTree = "<group>";
366397
};
367398
/* End PBXGroup section */
@@ -464,7 +495,7 @@
464495
isa = PBXResourcesBuildPhase;
465496
buildActionMask = 2147483647;
466497
files = (
467-
7F698E5D1D9D680C00F1561D /* test.json in Resources */,
498+
C5FF1DC128A80FFD0059573D /* test.json in Resources */,
468499
);
469500
runOnlyForDeploymentPostprocessing = 0;
470501
};
@@ -487,6 +518,7 @@
487518
7F7048E01D9D89FB003C99F6 /* Data+InputStream.swift in Sources */,
488519
7F7048DF1D9D89FB003C99F6 /* BodyParameters.swift in Sources */,
489520
7F7048E21D9D89FB003C99F6 /* JSONBodyParameters.swift in Sources */,
521+
C5725F4B28D8C36500810D7C /* Concurrency.swift in Sources */,
490522
7F7048D61D9D89F2003C99F6 /* SessionAdapter.swift in Sources */,
491523
7F7048EF1D9D8A12003C99F6 /* RequestError.swift in Sources */,
492524
7F7048E91D9D8A08003C99F6 /* FormURLEncodedDataParser.swift in Sources */,
@@ -513,6 +545,7 @@
513545
7F698E581D9D680C00F1561D /* RequestTests.swift in Sources */,
514546
ECA8314A1DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift in Sources */,
515547
7F698E5E1D9D680C00F1561D /* TestRequest.swift in Sources */,
548+
C5B144D828D8D7DC00E30ECD /* ConcurrencyTests.swift in Sources */,
516549
7F698E601D9D680C00F1561D /* TestSessionTask.swift in Sources */,
517550
0973EE35259E2DDC00879BA2 /* CombineTests.swift in Sources */,
518551
7FA1690D1D9D8C80006C982B /* HTTPStub.swift in Sources */,

Package.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.0
1+
// swift-tools-version:5.3
22
import PackageDescription
33

44
let package = Package(
@@ -18,7 +18,8 @@ let package = Package(
1818
),
1919
.testTarget(
2020
name: "APIKitTests",
21-
dependencies: ["APIKit"]
21+
dependencies: ["APIKit"],
22+
resources: [.process("Resources")]
2223
),
2324
],
2425
swiftLanguageVersions: [.v5]

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Session.send(request) { result in
3030

3131
## Requirements
3232

33-
- Swift 5.0 or later
33+
- Swift 5.3 or later
3434
- iOS 9.0 or later
3535
- Mac OS 10.10 or later
3636
- watchOS 2.0 or later
@@ -40,6 +40,8 @@ If you use Swift 2.2 or 2.3, try [APIKit 2.0.5](https://github.com/ishkawa/APIKi
4040

4141
If you use Swift 4.2 or before, try [APIKit 4.1.0](https://github.com/ishkawa/APIKit/tree/4.1.0).
4242

43+
If you use Swift 5.2 or before, try [APIKit 5.3.0](https://github.com/ishkawa/APIKit/tree/5.3.0).
44+
4345
## Installation
4446

4547
#### [Carthage](https://github.com/Carthage/Carthage)

Sources/APIKit/Combine/Combine.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public struct SessionTaskPublisher<Request: APIKit.Request>: Publisher {
6868
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
6969
public extension Session {
7070
/// Calls `sessionTaskPublisher(for:callbackQueue:)` of `Session.shared`.
71+
///
7172
/// - parameter request: The request to be sent.
7273
/// - parameter callbackQueue: The queue where the handler runs. If this parameters is `nil`, default `callbackQueue` of `Session` will be used.
7374
/// - returns: A publisher that wraps a session task for the request.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#if compiler(>=5.5.2) && canImport(_Concurrency)
2+
3+
import Foundation
4+
5+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
6+
public extension Session {
7+
/// Calls `response(for:callbackQueue:)` of `Session.shared`.
8+
///
9+
/// - parameter request: The request to be sent.
10+
/// - parameter callbackQueue: The queue where the handler runs. If this parameters is `nil`, default `callbackQueue` of `Session` will be used.
11+
/// - returns: `Request.Response`
12+
static func response<Request: APIKit.Request>(for request: Request, callbackQueue: CallbackQueue? = nil) async throws -> Request.Response {
13+
return try await shared.response(for: request, callbackQueue: callbackQueue)
14+
}
15+
16+
/// Convenience method to load `Request.Response` using an `Request`, creates and resumes an `SessionTask` internally.
17+
///
18+
/// - parameter request: The request to be sent.
19+
/// - parameter callbackQueue: The queue where the handler runs. If this parameters is `nil`, default `callbackQueue` of `Session` will be used.
20+
/// - returns: `Request.Response`
21+
func response<Request: APIKit.Request>(for request: Request, callbackQueue: CallbackQueue? = nil) async throws -> Request.Response {
22+
let cancellationHandler = SessionTaskCancellationHandler()
23+
return try await withTaskCancellationHandler(operation: {
24+
return try await withCheckedThrowingContinuation { continuation in
25+
Task {
26+
let sessionTask = createSessionTask(request, callbackQueue: callbackQueue) { result in
27+
continuation.resume(with: result)
28+
}
29+
await cancellationHandler.register(with: sessionTask)
30+
if await cancellationHandler.isTaskCancelled {
31+
sessionTask?.cancel()
32+
} else {
33+
sessionTask?.resume()
34+
}
35+
}
36+
}
37+
}, onCancel: {
38+
Task { await cancellationHandler.cancel() }
39+
})
40+
}
41+
}
42+
43+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
44+
private actor SessionTaskCancellationHandler {
45+
private var sessionTask: SessionTask?
46+
private(set) var isTaskCancelled = false
47+
48+
func register(with task: SessionTask?) {
49+
guard !isTaskCancelled else { return }
50+
guard sessionTask == nil else { return }
51+
sessionTask = task
52+
}
53+
54+
func cancel() {
55+
isTaskCancelled = true
56+
sessionTask?.cancel()
57+
}
58+
}
59+
60+
#endif

Sources/APIKit/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundlePackageType</key>
1616
<string>FMWK</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>5.3.0</string>
18+
<string>5.4.0</string>
1919
<key>CFBundleSignature</key>
2020
<string>????</string>
2121
<key>CFBundleVersion</key>

Sources/APIKit/Request.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,9 @@ public extension Request {
145145
return try response(from: passedObject, urlResponse: urlResponse)
146146
}
147147
}
148+
149+
public extension Request where Response == Void {
150+
func response(from object: Any, urlResponse: HTTPURLResponse) throws {
151+
return
152+
}
153+
}

0 commit comments

Comments
 (0)