Skip to content

Commit 2e33919

Browse files
gormsterEcona77
authored andcommitted
Allow DataParser to return typed objects
DataParser should not be required to return Any and have objects checked for type safety at runtime. This allows us to use the Swift build time type checking system with very minimal changes to existing code. The only API breaking change is that Request classes using the default JSONDataParser should now conform to JSONRequest, instead of just Request. This is because protocol extensions cannot declare default associated types. (cherry picked from commit 261af5f)
1 parent 5fac79c commit 2e33919

File tree

4 files changed

+20
-11
lines changed

4 files changed

+20
-11
lines changed

Sources/APIKit/DataParser/DataParser.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import Foundation
22

33
/// `DataParser` protocol provides interface to parse HTTP response body and to state Content-Type to accept.
44
public protocol DataParser {
5+
associatedtype Parsed
6+
57
/// Value for `Accept` header field of HTTP request.
68
var contentType: String? { get }
79

810
/// Return `Any` that expresses structure of response such as JSON and XML.
911
/// - Throws: `Error` when parser encountered invalid format data.
10-
func parse(data: Data) throws -> Any
12+
func parse(data: Data) throws -> Parsed
1113
}

Sources/APIKit/Request.swift

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Foundation
1010
public protocol Request {
1111
/// The response type associated with the request type.
1212
associatedtype Response
13+
associatedtype Parser: DataParser
1314

1415
/// The base URL.
1516
var baseURL: URL { get }
@@ -40,7 +41,7 @@ public protocol Request {
4041
var headerFields: [String: String] { get }
4142

4243
/// The parser object that states `Content-Type` to accept and parses response body.
43-
var dataParser: DataParser { get }
44+
var dataParser: Parser { get }
4445

4546
/// Intercepts `URLRequest` which is created by `Request.buildURLRequest()`. If an error is
4647
/// thrown in this method, the result of `Session.send()` turns `.failure(.requestError(error))`.
@@ -52,12 +53,12 @@ public protocol Request {
5253
/// The default implementation of this method is provided to throw `ResponseError.unacceptableStatusCode`
5354
/// if the HTTP status code is not in `200..<300`.
5455
/// - Throws: `Error`
55-
func intercept(object: Any, urlResponse: HTTPURLResponse) throws -> Any
56+
func intercept(object: Parser.Parsed, urlResponse: HTTPURLResponse) throws -> Parser.Parsed
5657

5758
/// Build `Response` instance from raw response object. This method is called after
5859
/// `intercept(object:urlResponse:)` if it does not throw any error.
5960
/// - Throws: `Error`
60-
func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response
61+
func response(from object: Parser.Parsed, urlResponse: HTTPURLResponse) throws -> Response
6162
}
6263

6364
public extension Request {
@@ -85,15 +86,11 @@ public extension Request {
8586
return [:]
8687
}
8788

88-
var dataParser: DataParser {
89-
return JSONDataParser(readingOptions: [])
90-
}
91-
9289
func intercept(urlRequest: URLRequest) throws -> URLRequest {
9390
return urlRequest
9491
}
9592

96-
func intercept(object: Any, urlResponse: HTTPURLResponse) throws -> Any {
93+
func intercept(object: Parser.Parsed, urlResponse: HTTPURLResponse) throws -> Parser.Parsed {
9794
guard 200..<300 ~= urlResponse.statusCode else {
9895
throw ResponseError.unacceptableStatusCode(urlResponse.statusCode)
9996
}
@@ -151,3 +148,13 @@ public extension Request where Response == Void {
151148
return
152149
}
153150
}
151+
152+
public protocol JSONRequest: Request {}
153+
154+
public extension JSONRequest {
155+
156+
var dataParser: JSONDataParser {
157+
return JSONDataParser(readingOptions: [])
158+
}
159+
160+
}

Tests/APIKitTests/SessionTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class SessionTests: XCTestCase {
174174
waitForExpectations(timeout: 1.0, handler: nil)
175175
}
176176

177-
struct AnotherTestRequest: Request {
177+
struct AnotherTestRequest: JSONRequest {
178178
typealias Response = Void
179179

180180
var baseURL: URL {

Tests/APIKitTests/TestComponents/TestRequest.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Foundation
22
import APIKit
33

4-
struct TestRequest: Request {
4+
struct TestRequest: JSONRequest {
55
var absoluteURL: URL? {
66
let urlRequest = try? buildURLRequest()
77
return urlRequest?.url

0 commit comments

Comments
 (0)