Browse Source

Deprecate responseJSON (#3502)

* Deprecate responseJSON.

* Fix tests.

* Fix tests for responseDecodable.

* Increase upload size for reliability.
Jon Shier 4 years ago
parent
commit
effb907b0e

+ 14 - 18
Documentation/AdvancedUsage.md

@@ -301,7 +301,7 @@ AF.request(...)
     .downloadProgress { progress in
         print(progress)
     }
-    .responseDecodable(of: SomeType.self) { response in
+    .responseDecodable(of: DecodableType.self) { response in
         debugPrint(response)
     }
 ```
@@ -323,7 +323,7 @@ Alamofire’s `RedirectHandler` protocol provides control and customization of r
 let redirector = Redirector(behavior: .follow)
 AF.request(...)
     .redirect(using: redirector)
-    .responseDecodable(of: SomeType.self) { response in 
+    .responseDecodable(of: DecodableType.self) { response in 
         debugPrint(response)
     }
 ```
@@ -337,7 +337,7 @@ Alamofire’s `CachedResponseHandler` protocol provides control and customizatio
 let cacher = ResponseCacher(behavior: .cache)
 AF.request(...)
     .cacheResponse(using: cacher)
-    .responseDecodable(of: SomeType.self) { response in 
+    .responseDecodable(of: DecodableType.self) { response in 
         debugPrint(response)
     }
 ```
@@ -352,7 +352,7 @@ Adding a credential to automatically reply to any HTTP authentication challenge
 ```swift
 AF.request(...)
     .authenticate(username: "user@example.domain", password: "password")
-    .responseDecodable(of: SomeType.self) { response in 
+    .responseDecodable(of: DecodableType.self) { response in 
         debugPrint(response)
     }
 ```
@@ -365,7 +365,7 @@ Additionally, adding a raw `URLCredential` is just as easy:
 let credential = URLCredential(...)
 AF.request(...)
     .authenticate(using: credential)
-    .responseDecodable(of: SomeType.self) { response in 
+    .responseDecodable(of: DecodableType.self) { response in 
         debugPrint(response)
     }
 ```
@@ -383,7 +383,7 @@ AF.request(...)
     .onURLRequestCreation { request in
         print(request)
     }
-    .responseDecodable(of: SomeType.self) { response in
+    .responseDecodable(of: DecodableType.self) { response in
         debugPrint(response)
     }
 ```
@@ -398,7 +398,7 @@ AF.request(...)
     .onURLSessionTaskCreation { task in
         print(task)
     }
-    .responseDecodable(of: SomeType.self) { response in
+    .responseDecodable(of: DecodableType.self) { response in
         debugPrint(response)
     }
 ```
@@ -413,7 +413,7 @@ Alamofire gathers `URLSessionTaskMetrics` values for every `URLSessionTask` perf
 
 ```swift
 AF.request(...)
-    .responseDecodable(of: SomeType.self) { response in {
+    .responseDecodable(of: DecodableType.self) { response in {
         print(response.metrics)
     }
 ```
@@ -1030,7 +1030,6 @@ Alamofire includes a few common responses handlers, including:
 
 - `responseData(queue:completionHandler)`: Validates and preprocesses the response `Data` using `DataResponseSerializer`.
 - `responseString(queue:encoding:completionHandler:)`: Parses the response `Data` as a `String` using the provided `String.Encoding`.
-- `responseJSON(queue:options:completionHandler)`: Parses the response `Data` using `JSONSerialization` using the provided `JSONSerialization.ReadingOptions`. Using this method is not recommended and is only offered for compatibility with existing Alamofire usage. Instead, `responseDecodable` should be used.
 - `responseDecodable(of:queue:decoder:completionHandler:)`: Parses the response `Data` into the provided or inferred `Decodable` type using the provided `DataDecoder`. Uses `JSONDecoder` by default. Recommend method for JSON and generic response parsing.
 
 #### `DataResponseSerializer`
@@ -1039,9 +1038,6 @@ Calling `responseData(queue:completionHandler:)` on `DataRequest` or `DownloadRe
 #### `StringResponseSerializer`
 Calling `responseString(queue:encoding:completionHandler)` on `DataRequest` or `DownloadRequest` uses a `StringResponseSerializer` to validate that `Data` has been returned appropriately (no empty responses unless allowed by the `emptyResponseMethods` and `emptyResponseCodes`) and passes that `Data` through the `dataPreprocessor`. The preprocessed `Data` is then used to initialize a `String` using the `String.Encoding` parsed from the `HTTPURLResponse`.
 
-#### `JSONResponseSerializer`
-Calling `responseJSON(queue:options:completionHandler)` on `DataRequest` or `DownloadRequest` uses a `JSONResponseSerializer` to validate that `Data` has been returned appropriately (no empty responses unless allowed by the `emptyResponseMethods` and `emptyResponseCodes`) and passes that `Data` through the `dataPreprocessor`. The preprocessed `Data` is then passed through `JSONSerialization.jsonObject(with:options:)` with the provided options. This serializer is no longer recommended. Instead, using the `DecodableResponseSerializer` provides a better Swift experience.
-
 #### `DecodableResponseSerializer`
 Calling `responseDecodable(of:queue:decoder:completionHandler)` on `DataRequest` or `DownloadRequest` uses a `DecodableResponseSerializer`to validate that `Data` has been returned appropriately (no empty responses unless allowed by the `emptyResponseMethods` and `emptyResponseCodes`) and passes that `Data` through the `dataPreprocessor`. The preprocessed `Data` is then passed through the provided `DataDecoder` and parsed into the provided or inferred `Decodable` type.
 
@@ -1052,7 +1048,7 @@ In addition to the flexible `ResponseSerializer`s included with Alamofire, there
 Using an existing `ResponseSerializer` and then transforming the output is one of the simplest ways of customizing response handlers. Both `DataResponse` and `DownloadResponse` have `map`, `tryMap`, `mapError`, and `tryMapError` methods that can transform responses while preserving the metadata associated with the response. For example, extracting a property from a `Decodable` response can be achieved using `map`, while also preserving any previous parsing errors.
 
 ```swift
-AF.request(...).responseDecodable(of: SomeType.self) { response in
+AF.request(...).responseDecodable(of: DecodableType.self) { response in
     let propertyResponse = response.map { $0.someProperty }
 
     debugPrint(propertyResponse)
@@ -1062,7 +1058,7 @@ AF.request(...).responseDecodable(of: SomeType.self) { response in
 Transforms that throw errors can also be used with `tryMap`, perhaps to perform validation:
 
 ```swift
-AF.request(..).responseDecodable(of: SomeType.self) { response in
+AF.request(..).responseDecodable(of: DecodableType.self) { response in
     let propertyResponse = response.tryMap { try $0.someProperty.validated() }
 
     debugPrint(propertyResponse)
@@ -1132,7 +1128,7 @@ AF.streamRequest(...).responseStream(using: DecodableStreamSerializer<DecodableT
 ```
 
 ## Using Alamofire with Combine
-On systems supporting the Combine framework, Alamofire offers the ability to publish responses using a custom `Publisher` type. These publishers work much like Alamofire's response handlers. They are chained onto requests and like response handlers, should come after other API like `validate()`. For example:
+On systems supporting the Combine framework, Alamofire offers the ability to publish responses using a custom `Publisher` type. These publishers work much like Alamofire's response handlers. They are chained onto requests and, like response handlers, should come after other API like `validate()`. For example:
 
 ```swift
 AF.request(...).publishDecodable(type: DecodableType.self)
@@ -1218,10 +1214,10 @@ manager?.startListening { status in
 There are some important things to remember when using network reachability to determine what to do next.
 
 - **DO NOT** use Reachability to determine if a network request should be sent.
-	- You should **ALWAYS** send it.
+    - You should **ALWAYS** send it.
 - When reachability is restored, use the event to retry failed network requests.
-	- Even though the network requests may still fail, this is a good moment to retry them.
+    - Even though the network requests may still fail, this is a good moment to retry them.
 - The network reachability status can be useful for determining why a network request may have failed.
-	- If a network request fails, it is more useful to tell the user that the network request failed due to being offline rather than a more technical error, such as "request timed out."
+    - If a network request fails, it is more useful to tell the user that the network request failed due to being offline rather than a more technical error, such as "request timed out."
 
 Alternatively, using a `RequestRetrier`, like the built in `RetryPolicy`, instead of reachability updates to retry requests which failed to a network failure will likely be simpler and more reliable. By default, `RetryPolicy` will retry idempotent requests on a variety of error conditions, including an offline network connection.

+ 29 - 47
Documentation/Usage.md

@@ -149,6 +149,8 @@ If you need to use an HTTP method that Alamofire's `HTTPMethod` type doesn't sup
 extension HTTPMethod {
     static let custom = HTTPMethod(rawValue: "CUSTOM")
 }
+
+AF.request("https://httpbin.org/headers", method: .custom)
 ```
 
 ### Setting Other `URLRequest` Properties
@@ -395,7 +397,7 @@ let headers: HTTPHeaders = [
     "Accept": "application/json"
 ]
 
-AF.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
+AF.request("https://httpbin.org/headers", headers: headers).responseDecodable(of: DecodableType.self) { response in
     debugPrint(response)
 }
 ```
@@ -408,7 +410,7 @@ let headers: HTTPHeaders = [
     .accept("application/json")
 ]
 
-AF.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
+AF.request("https://httpbin.org/headers", headers: headers).responseDecodable(of: DecodableType.self) { response in
     debugPrint(response)
 }
 ```
@@ -432,7 +434,7 @@ By default, Alamofire treats any completed request to be successful, regardless
 The `validate()` API automatically validates that status codes are within the `200..<300` range, and that the `Content-Type` header of the response matches the `Accept` header of the request, if one is provided.
 
 ```swift
-AF.request("https://httpbin.org/get").validate().responseJSON { response in
+AF.request("https://httpbin.org/get").validate().responseData { response in
     debugPrint(response)
 }
 ```
@@ -457,21 +459,21 @@ AF.request("https://httpbin.org/get")
 
 Alamofire's `DataRequest` and `DownloadRequest` both have a corresponding response type: `DataResponse<Success, Failure: Error>` and `DownloadResponse<Success, Failure: Error>`. Both of these are composed of two generics: the serialized type and the error type. By default, all response values will produce the `AFError` error type (i.e. `DataResponse<Success, AFError>`). Alamofire uses the simpler `AFDataResponse<Success>` and `AFDownloadResponse<Success>`, in its public API, which always have `AFError` error types. `UploadRequest`, a subclass of `DataRequest`, uses the same `DataResponse` type.
 
-Handling the `DataResponse` of a `DataRequest` or `UploadRequest` made in Alamofire involves chaining a response handler like `responseJSON` onto the `DataRequest`:
+Handling the `DataResponse` of a `DataRequest` or `UploadRequest` made in Alamofire involves chaining a response handler like `responseDecodable` onto the `DataRequest`:
 
 ```swift
-AF.request("https://httpbin.org/get").responseJSON { response in
+AF.request("https://httpbin.org/get").responseDecodable(of: DecodableType.self) { response in
     debugPrint(response)
 }
 ```
 
-In the above example, the `responseJSON` handler is added to the `DataRequest` to be executed once the `DataRequest` is complete. The closure passed to the handler receives the `AFDataResponse<Any>` value produced by the `JSONResponseSerializer` from the response properties.
+In the above example, the `responseDecodable` handler is added to the `DataRequest` to be executed once the `DataRequest` is complete. The closure passed to the handler receives the `DataResponse<DecodableType, AFError>` value produced by the `DecodableResponseSerializer` from the `URLRequest`, `HTTPURLResponse`, `Data`, and `Error` produced by the request.
 
-Rather than blocking execution to wait for a response from the server,  this closure is added as a [callback](https://en.wikipedia.org/wiki/Callback_%28computer_programming%29) to handle the response once it's received. The result of a request is only available inside the scope of a response closure. Any execution contingent on the response or data received from the server must be done within a response closure.
+Rather than blocking execution to wait for a response from the server, this closure is added as a [callback](https://en.wikipedia.org/wiki/Callback_%28computer_programming%29) to handle the response once it's received. The result of a request is only available inside the scope of a response closure. Any execution contingent on the response or data received from the server must be done within a response closure.
 
 > Networking in Alamofire is done _asynchronously_. Asynchronous programming may be a source of frustration to programmers unfamiliar with the concept, but there are [very good reasons](https://developer.apple.com/library/ios/qa/qa1693/_index.html) for doing it this way.
 
-Alamofire contains six different data response handlers by default, including:
+Alamofire contains five different data response handlers by default, including:
 
 ```swift
 // Response Handler - Unserialized Response
@@ -498,14 +500,6 @@ func responseString(queue: DispatchQueue = .main,
                     emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods,
                     completionHandler: @escaping (AFDataResponse<String>) -> Void) -> Self
 
-// Response JSON Handler - Serialized into Any Using JSONSerialization
-func responseJSON(queue: DispatchQueue = .main,
-                  dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
-                  emptyResponseCodes: Set<Int> = JSONResponseSerializer.defaultEmptyResponseCodes,
-                  emptyRequestMethods: Set<HTTPMethod> = JSONResponseSerializer.defaultEmptyRequestMethods,
-                  options: JSONSerialization.ReadingOptions = .allowFragments,
-                  completionHandler: @escaping (AFDataResponse<Any>) -> Void) -> Self
-
 // Response Decodable Handler - Serialized into Decodable Type
 func responseDecodable<T: Decodable>(of type: T.Type = T.self,
                                      queue: DispatchQueue = .main,
@@ -554,26 +548,14 @@ AF.request("https://httpbin.org/get").responseString { response in
 
 > If no encoding is specified, Alamofire will use the text encoding specified in the `HTTPURLResponse` from the server. If the text encoding cannot be determined by the server response, it defaults to `.isoLatin1`.
 
-#### Response JSON Handler
-
-The `responseJSON` handler uses a `JSONResponseSerializer` to convert the `Data` returned by the server into an `Any` type using the specified `JSONSerialization.ReadingOptions`. If no errors occur and the server data is successfully serialized into a JSON object, the response `AFResult` will be a `.success` and the `value` will be of type `Any`.
-
-```swift
-AF.request("https://httpbin.org/get").responseJSON { response in
-    debugPrint("Response: \(response)")
-}
-```
-
-> JSON serialization in `responseJSON` is handled by the `JSONSerialization` API from the `Foundation` framework.
-
 #### Response `Decodable` Handler
 
 The `responseDecodable` handler uses a `DecodableResponseSerializer` to convert the `Data` returned by the server into the passed `Decodable` type using the specified `DataDecoder` (a protocol abstraction for `Decoder`s which can decode from `Data`). If no errors occur and the server data is successfully decoded into a `Decodable` type, the response `Result` will be a `.success` and the `value` will be of the passed type.
 
 ```swift
-struct HTTPBinResponse: Decodable { let url: String }
+struct DecodableType: Decodable { let url: String }
 
-AF.request("https://httpbin.org/get").responseDecodable(of: HTTPBinResponse.self) { response in
+AF.request("https://httpbin.org/get").responseDecodable(of: DecodableType.self) { response in
     debugPrint("Response: \(response)")
 }
 ```
@@ -587,8 +569,8 @@ Alamofire.request("https://httpbin.org/get")
     .responseString { response in
         print("Response String: \(response.value)")
     }
-    .responseJSON { response in
-        print("Response JSON: \(response.value)")
+    .responseDecodable(of: DecodableType.self) { response in
+        print("Response DecodableType: \(response.value)")
     }
 ```
 
@@ -596,13 +578,13 @@ Alamofire.request("https://httpbin.org/get")
 
 #### Response Handler Queue
 
-Closures passed to response handlers are executed on the `.main` queue by default, but a specific `DispatchQueue` can be passed on which to execute the closure. Actual serialization work (conversion of `Data` to some other type) is always executed on a background queue.
+Closures passed to response handlers are executed on the `.main` queue by default, but a specific `DispatchQueue` can be passed on which to execute the closure. Actual serialization work (conversion of `Data` to some other type) is always executed in the background on either the `rootQueue` or the `serializationQueue`, if one was provided, of the `Session` issuing the request.
 
 ```swift
 let utilityQueue = DispatchQueue.global(qos: .utility)
 
-AF.request("https://httpbin.org/get").responseJSON(queue: utilityQueue) { response in
-    print("Executed on utility queue.")
+AF.request("https://httpbin.org/get").responseDecodable(of: DecodableType.self, queue: utilityQueue) { response in
+    print("This closure is executed on utilityQueue.")
     debugPrint(response)
 }
 ```
@@ -636,7 +618,7 @@ let password = "password"
 
 AF.request("https://httpbin.org/basic-auth/\(user)/\(password)")
     .authenticate(username: user, password: password)
-    .responseJSON { response in
+    .responseDecodable(of: DecodableType.self) { response in
         debugPrint(response)
     }
 ```
@@ -651,7 +633,7 @@ let credential = URLCredential(user: user, password: password, persistence: .for
 
 AF.request("https://httpbin.org/basic-auth/\(user)/\(password)")
     .authenticate(with: credential)
-    .responseJSON { response in
+    .responseDecodable(of: DecodableType.self) { response in
         debugPrint(response)
     }
 ```
@@ -669,7 +651,7 @@ let password = "password"
 let headers: HTTPHeaders = [.authorization(username: user, password: password)]
 
 AF.request("https://httpbin.org/basic-auth/user/password", headers: headers)
-    .responseJSON { response in
+    .responseDecodable(of: DecodableType.self) { response in
         debugPrint(response)
     }
 ```
@@ -682,13 +664,13 @@ In addition to fetching data into memory, Alamofire also provides the `Session.d
 
 ```swift
 AF.download("https://httpbin.org/image/png").responseURL { response in
-    // Read file from provided URL.
+    // Read file from provided file URL.
 }
 ```
 
 In addition to having the same response handlers that `DataRequest` does, `DownloadRequest` also includes `responseURL`. Unlike the other response handlers, this handler just returns the `URL` containing the location of the downloaded data and does not read the `Data` from disk.
 
-Other response handlers, like `responseDecodable`, involve reading the response `Data` from disk. This may involve reading large amounts of data into memory, so it's important to keep that in mind when using those handlers.
+Other response handlers, like `responseDecodable`, involve reading the response `Data` from disk. This may involve reading large amounts of data into memory, so it's important to keep that in mind when using those handlers for downloads.
 
 #### Download File Destination
 
@@ -796,7 +778,7 @@ When sending relatively small amounts of data to a server using JSON or URL enco
 ```swift
 let data = Data("data".utf8)
 
-AF.upload(data, to: "https://httpbin.org/post").responseDecodable(of: HTTPBinResponse.self) { response in
+AF.upload(data, to: "https://httpbin.org/post").responseDecodable(of: DecodableType.self) { response in
     debugPrint(response)
 }
 ```
@@ -806,7 +788,7 @@ AF.upload(data, to: "https://httpbin.org/post").responseDecodable(of: HTTPBinRes
 ```swift
 let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")
 
-AF.upload(fileURL, to: "https://httpbin.org/post").responseDecodable(of: HTTPBinResponse.self) { response in
+AF.upload(fileURL, to: "https://httpbin.org/post").responseDecodable(of: DecodableType.self) { response in
     debugPrint(response)
 }
 ```
@@ -818,7 +800,7 @@ AF.upload(multipartFormData: { multipartFormData in
     multipartFormData.append(Data("one".utf8), withName: "one")
     multipartFormData.append(Data("two".utf8), withName: "two")
 }, to: "https://httpbin.org/post")
-    .responseDecodable(of: HTTPBinResponse.self) { response in
+    .responseDecodable(of: DecodableType.self) { response in
         debugPrint(response)
     }
 ```
@@ -837,7 +819,7 @@ AF.upload(fileURL, to: "https://httpbin.org/post")
     .downloadProgress { progress in
         print("Download Progress: \(progress.fractionCompleted)")
     }
-    .responseDecodable(of: HTTPBinResponse.self) { response in
+    .responseDecodable(of: DecodableType.self) { response in
         debugPrint(response)
     }
 ```
@@ -1029,7 +1011,7 @@ AF.streamRequest(...).responseStream { stream in
 Alamofire gathers `URLSessionTaskMetrics` for every `Request`. `URLSessionTaskMetrics` encapsulate some fantastic statistical information about the underlying network connection and request and response timing.
 
 ```swift
-AF.request("https://httpbin.org/get").responseJSON { response in
+AF.request("https://httpbin.org/get").responseDecodable(of: DecodableType.self) { response in
     print(response.metrics)
 }
 ```
@@ -1045,7 +1027,7 @@ AF.request("https://httpbin.org/get")
     .cURLDescription { description in
         print(description)
     }
-    .responseJSON { response in
+    .responseDecodable(of: DecodableType.self) { response in
         debugPrint(response.metrics)
     }
 ```
@@ -1057,6 +1039,6 @@ $ curl -v \
 -X GET \
 -H "Accept-Language: en;q=1.0" \
 -H "Accept-Encoding: br;q=1.0, gzip;q=0.9, deflate;q=0.8" \
--H "User-Agent: Demo/1.0 (com.demo.Demo; build:1; iOS 13.0.0) Alamofire/1.0" \
+-H "User-Agent: Demo/1.0 (com.demo.Demo; build:1; iOS 15.0.0) Alamofire/1.0" \
 "https://httpbin.org/get"
 ```

+ 3 - 0
Source/ResponseSerialization.swift

@@ -764,6 +764,7 @@ extension DownloadRequest {
 /// A `ResponseSerializer` that decodes the response data using `JSONSerialization`. By default, a request returning
 /// `nil` or no data is considered an error. However, if the request has an `HTTPMethod` or the response has an
 /// HTTP status code valid for empty responses, then an `NSNull` value is returned.
+@available(*, deprecated, message: "JSONResponseSerializer deprecated and will be removed in Alamofire 6. Use DecodableResponseSerializer instead.")
 public final class JSONResponseSerializer: ResponseSerializer {
     public let dataPreprocessor: DataPreprocessor
     public let emptyResponseCodes: Set<Int>
@@ -825,6 +826,7 @@ extension DataRequest {
     ///   - completionHandler:   A closure to be executed once the request has finished.
     ///
     /// - Returns:               The request.
+    @available(*, deprecated, message: "responseJSON deprecated and will be removed in Alamofire 6. Use responseDecodable instead.")
     @discardableResult
     public func responseJSON(queue: DispatchQueue = .main,
                              dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
@@ -857,6 +859,7 @@ extension DownloadRequest {
     ///   - completionHandler:   A closure to be executed once the request has finished.
     ///
     /// - Returns:               The request.
+    @available(*, deprecated, message: "responseJSON deprecated and will be removed in Alamofire 6. Use responseDecodable instead.")
     @discardableResult
     public func responseJSON(queue: DispatchQueue = .main,
                              dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,

+ 14 - 16
Tests/DownloadTests.swift

@@ -600,12 +600,12 @@ final class DownloadResumeDataTestCase: BaseTestCase {
         XCTAssertEqual(response?.resumeData, download.resumeData)
     }
 
-    func testThatCancelledDownloadResumeDataIsAvailableWithJSONResponseSerializer() {
+    func testThatCancelledDownloadResumeDataIsAvailableWithDecodableResponseSerializer() {
         // Given
         let expectation = self.expectation(description: "Download should be cancelled")
         var cancelled = false
 
-        var response: DownloadResponse<Any, AFError>?
+        var response: DownloadResponse<TestResponse, AFError>?
 
         // When
         let download = AF.download(.download())
@@ -617,7 +617,7 @@ final class DownloadResumeDataTestCase: BaseTestCase {
                 cancelled = true
             }
         }
-        download.responseJSON { resp in
+        download.responseDecodable(of: TestResponse.self) { resp in
             response = resp
             expectation.fulfill()
         }
@@ -746,10 +746,9 @@ final class DownloadResponseMapTestCase: BaseTestCase {
         var response: DownloadResponse<String, AFError>?
 
         // When
-        AF.download(.get, parameters: ["foo": "bar"]).responseJSON { resp in
-            response = resp.map { json in
-                // json["args"]["foo"] is "bar": use this invariant to test the map function
-                ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
+        AF.download(.get, parameters: ["foo": "bar"]).responseDecodable(of: TestResponse.self) { resp in
+            response = resp.map { response in
+                response.args?["foo"] ?? "invalid"
             }
 
             expectation.fulfill()
@@ -775,7 +774,7 @@ final class DownloadResponseMapTestCase: BaseTestCase {
         var response: DownloadResponse<String, AFError>?
 
         // When
-        AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
+        AF.download(urlString, parameters: ["foo": "bar"]).responseDecodable(of: TestResponse.self) { resp in
             response = resp.map { _ in "ignored" }
             expectation.fulfill()
         }
@@ -803,10 +802,9 @@ final class DownloadResponseTryMapTestCase: BaseTestCase {
         var response: DownloadResponse<String, Error>?
 
         // When
-        AF.download(.get, parameters: ["foo": "bar"]).responseJSON { resp in
-            response = resp.tryMap { json in
-                // json["args"]["foo"] is "bar": use this invariant to test the map function
-                ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
+        AF.download(.get, parameters: ["foo": "bar"]).responseDecodable(of: TestResponse.self) { resp in
+            response = resp.tryMap { response in
+                response.args?["foo"] ?? "invalid"
             }
 
             expectation.fulfill()
@@ -833,7 +831,7 @@ final class DownloadResponseTryMapTestCase: BaseTestCase {
         var response: DownloadResponse<String, Error>?
 
         // When
-        AF.download(.get, parameters: ["foo": "bar"]).responseJSON { resp in
+        AF.download(.get, parameters: ["foo": "bar"]).responseDecodable(of: TestResponse.self) { resp in
             response = resp.tryMap { _ in
                 throw TransformError()
             }
@@ -865,7 +863,7 @@ final class DownloadResponseTryMapTestCase: BaseTestCase {
         var response: DownloadResponse<String, Error>?
 
         // When
-        AF.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
+        AF.download(urlString, parameters: ["foo": "bar"]).responseDecodable(of: TestResponse.self) { resp in
             response = resp.tryMap { _ in "ignored" }
             expectation.fulfill()
         }
@@ -889,10 +887,10 @@ final class DownloadResponseMapErrorTestCase: BaseTestCase {
         let urlString = String.nonexistentDomain
         let expectation = self.expectation(description: "request should not succeed")
 
-        var response: DownloadResponse<Any, TestError>?
+        var response: DownloadResponse<TestResponse, TestError>?
 
         // When
-        AF.download(urlString).responseJSON { resp in
+        AF.download(urlString).responseDecodable(of: TestResponse.self) { resp in
             response = resp.mapError { error in
                 TestError.error(error: error)
             }

+ 29 - 29
Tests/RequestTests.swift

@@ -100,11 +100,11 @@ final class RequestResponseTestCase: BaseTestCase {
 
         let expectation = self.expectation(description: "request should succeed")
 
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
         AF.request(.method(.post), parameters: parameters)
-            .responseJSON { closureResponse in
+            .responseDecodable(of: TestResponse.self) { closureResponse in
                 response = closureResponse
                 expectation.fulfill()
             }
@@ -116,7 +116,7 @@ final class RequestResponseTestCase: BaseTestCase {
         XCTAssertNotNil(response?.response)
         XCTAssertNotNil(response?.data)
 
-        if let json = response?.result.success as? [String: Any], let form = json["form"] as? [String: String] {
+        if let form = response?.result.success?.form {
             XCTAssertEqual(form["french"], parameters["french"])
             XCTAssertEqual(form["japanese"], parameters["japanese"])
             XCTAssertEqual(form["arabic"], parameters["arabic"])
@@ -149,11 +149,11 @@ final class RequestResponseTestCase: BaseTestCase {
 
         let expectation = self.expectation(description: "request should succeed")
 
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
         AF.request(Endpoint.method(.post), method: .post, parameters: parameters)
-            .responseJSON { closureResponse in
+            .responseDecodable(of: TestResponse.self) { closureResponse in
                 response = closureResponse
                 expectation.fulfill()
             }
@@ -166,7 +166,7 @@ final class RequestResponseTestCase: BaseTestCase {
         XCTAssertNotNil(response?.data)
         XCTAssertEqual(response?.result.isSuccess, true)
 
-        if let json = response?.result.success as? [String: Any], let form = json["form"] as? [String: String] {
+        if let form = response?.result.success?.form {
             XCTAssertEqual(form["email"], parameters["email"])
             XCTAssertEqual(form["png_image"], parameters["png_image"])
             XCTAssertEqual(form["jpeg_image"], parameters["jpeg_image"])
@@ -183,10 +183,10 @@ final class RequestResponseTestCase: BaseTestCase {
         let queue = DispatchQueue(label: "org.alamofire.testSerializationQueue")
         let manager = Session(serializationQueue: queue)
         let expectation = self.expectation(description: "request should complete")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
-        manager.request(Endpoint.get).responseJSON { resp in
+        manager.request(.get).responseDecodable(of: TestResponse.self) { resp in
             response = resp
             expectation.fulfill()
         }
@@ -203,10 +203,10 @@ final class RequestResponseTestCase: BaseTestCase {
         let serializationQueue = DispatchQueue(label: "org.alamofire.testSerializationQueue")
         let manager = Session(requestQueue: requestQueue, serializationQueue: serializationQueue)
         let expectation = self.expectation(description: "request should complete")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
-        manager.request(Endpoint.get).responseJSON { resp in
+        manager.request(.get).responseDecodable(of: TestResponse.self) { resp in
             response = resp
             expectation.fulfill()
         }
@@ -225,11 +225,11 @@ final class RequestResponseTestCase: BaseTestCase {
         let count = 10
         let expectation = self.expectation(description: "request should complete")
         expectation.expectedFulfillmentCount = count
-        var responses: [DataResponse<Any, AFError>] = []
+        var responses: [DataResponse<TestResponse, AFError>] = []
 
         // When
         DispatchQueue.concurrentPerform(iterations: count) { _ in
-            session.request(.default).responseJSON { resp in
+            session.request(.default).responseDecodable(of: TestResponse.self) { resp in
                 responses.append(resp)
                 expectation.fulfill()
             }
@@ -666,8 +666,8 @@ final class RequestResponseTestCase: BaseTestCase {
         // Given
         let session = Session()
 
-        var response1: DataResponse<Any, AFError>?
-        var response2: DataResponse<Any, AFError>?
+        var response1: DataResponse<TestResponse, AFError>?
+        var response2: DataResponse<TestResponse, AFError>?
 
         let expect = expectation(description: "both response serializer completions should be called")
         expect.expectedFulfillmentCount = 2
@@ -675,11 +675,11 @@ final class RequestResponseTestCase: BaseTestCase {
         // When
         let request = session.request(.default)
 
-        request.responseJSON { resp in
+        request.responseDecodable(of: TestResponse.self) { resp in
             response1 = resp
             expect.fulfill()
 
-            request.responseJSON { resp in
+            request.responseDecodable(of: TestResponse.self) { resp in
                 response2 = resp
                 expect.fulfill()
             }
@@ -698,9 +698,9 @@ final class RequestResponseTestCase: BaseTestCase {
         // Given
         let session = Session()
 
-        var response1: DataResponse<Any, AFError>?
-        var response2: DataResponse<Any, AFError>?
-        var response3: DataResponse<Any, AFError>?
+        var response1: DataResponse<TestResponse, AFError>?
+        var response2: DataResponse<TestResponse, AFError>?
+        var response3: DataResponse<TestResponse, AFError>?
 
         let expect = expectation(description: "all response serializer completions should be called")
         expect.expectedFulfillmentCount = 3
@@ -708,15 +708,15 @@ final class RequestResponseTestCase: BaseTestCase {
         // When
         let request = session.request(.default)
 
-        request.responseJSON { resp in
+        request.responseDecodable(of: TestResponse.self) { resp in
             response1 = resp
             expect.fulfill()
 
-            request.responseJSON { resp in
+            request.responseDecodable(of: TestResponse.self) { resp in
                 response2 = resp
                 expect.fulfill()
 
-                request.responseJSON { resp in
+                request.responseDecodable(of: TestResponse.self) { resp in
                     response3 = resp
                     expect.fulfill()
                 }
@@ -736,21 +736,21 @@ final class RequestResponseTestCase: BaseTestCase {
         let session = Session()
         let request = session.request(.default)
 
-        var response1: DataResponse<Any, AFError>?
-        var response2: DataResponse<Any, AFError>?
-        var response3: DataResponse<Any, AFError>?
+        var response1: DataResponse<TestResponse, AFError>?
+        var response2: DataResponse<TestResponse, AFError>?
+        var response3: DataResponse<TestResponse, AFError>?
 
         // When
         let expect1 = expectation(description: "response serializer 1 completion should be called")
-        request.responseJSON { response1 = $0; expect1.fulfill() }
+        request.responseDecodable(of: TestResponse.self) { response1 = $0; expect1.fulfill() }
         waitForExpectations(timeout: timeout)
 
         let expect2 = expectation(description: "response serializer 2 completion should be called")
-        request.responseJSON { response2 = $0; expect2.fulfill() }
+        request.responseDecodable(of: TestResponse.self) { response2 = $0; expect2.fulfill() }
         waitForExpectations(timeout: timeout)
 
         let expect3 = expectation(description: "response serializer 3 completion should be called")
-        request.responseJSON { response3 = $0; expect3.fulfill() }
+        request.responseDecodable(of: TestResponse.self) { response3 = $0; expect3.fulfill() }
         waitForExpectations(timeout: timeout)
 
         // Then
@@ -762,7 +762,7 @@ final class RequestResponseTestCase: BaseTestCase {
 
 // MARK: -
 
-class RequestDescriptionTestCase: BaseTestCase {
+final class RequestDescriptionTestCase: BaseTestCase {
     func testRequestDescription() {
         // Given
         let url = Endpoint().url

+ 19 - 0
Tests/ResponseSerializationTests.swift

@@ -320,6 +320,7 @@ final class DataResponseSerializationTestCase: BaseTestCase {
 
     // MARK: JSONResponseSerializer
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenDataIsNil() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -334,6 +335,7 @@ final class DataResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.failure?.asAFError?.isInputDataNilOrZeroLength, true)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenDataIsEmpty() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -348,6 +350,7 @@ final class DataResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.failure?.asAFError?.isInputDataNilOrZeroLength, true)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerSucceedsWhenDataIsValidJSON() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -362,6 +365,7 @@ final class DataResponseSerializationTestCase: BaseTestCase {
         XCTAssertNil(result.failure)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenDataIsInvalidJSON() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -378,6 +382,7 @@ final class DataResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual((result.failure?.asAFError?.underlyingError as? CocoaError)?.code, .propertyListReadCorrupt)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenErrorIsNotNil() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -392,6 +397,7 @@ final class DataResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.failure?.asAFError?.isInputDataNilOrZeroLength, true)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenDataIsNilWithNonEmptyResponseStatusCode() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -407,6 +413,7 @@ final class DataResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.failure?.asAFError?.isInputDataNilOrZeroLength, true)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerSucceedsWhenDataIsNilWithGETRequestAnd204ResponseStatusCode() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -423,6 +430,7 @@ final class DataResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.success as? NSNull, NSNull())
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerSucceedsWhenDataIsNilWithGETRequestAnd205ResponseStatusCode() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -439,6 +447,7 @@ final class DataResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.success as? NSNull, NSNull())
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerSucceedsWhenDataIsNilWithHEADRequestAnd200ResponseStatusCode() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -1050,6 +1059,7 @@ final class DownloadResponseSerializationTestCase: BaseTestCase {
 
     // MARK: Tests - JSON Response Serializer
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenFileURLIsNil() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -1064,6 +1074,7 @@ final class DownloadResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.failure?.asAFError?.isInputFileNil, true)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenFileURLIsInvalid() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -1078,6 +1089,7 @@ final class DownloadResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.failure?.asAFError?.isInputFileReadFailed, true)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenFileDataIsEmpty() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -1092,6 +1104,7 @@ final class DownloadResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.failure?.asAFError?.isInputDataNilOrZeroLength, true)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerSucceedsWhenDataIsValidJSON() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -1105,6 +1118,7 @@ final class DownloadResponseSerializationTestCase: BaseTestCase {
         XCTAssertNil(result.failure)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenDataIsInvalidJSON() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -1120,6 +1134,7 @@ final class DownloadResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual((result.failure?.asAFError?.underlyingError as? CocoaError)?.code, .propertyListReadCorrupt)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenErrorIsNotNil() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -1134,6 +1149,7 @@ final class DownloadResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.failure?.asAFError?.isInputFileNil, true)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerFailsWhenDataIsNilWithNonEmptyResponseStatusCode() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -1149,6 +1165,7 @@ final class DownloadResponseSerializationTestCase: BaseTestCase {
         XCTAssertEqual(result.failure?.asAFError?.isInputFileNil, true)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerSucceedsWhenDataIsNilWithEmptyResponseStatusCode() {
         // Given
         let serializer = JSONResponseSerializer()
@@ -1267,6 +1284,7 @@ final class DataPreprocessorSerializationTests: BaseTestCase {
         XCTAssertNotNil(result.failure)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerProperlyCallsSuccessfulDataPreprocessor() {
         // Given
         let preprocessor = DropFirst()
@@ -1282,6 +1300,7 @@ final class DataPreprocessorSerializationTests: BaseTestCase {
         XCTAssertNil(result.failure)
     }
 
+    @available(*, deprecated)
     func testThatJSONResponseSerializerProperlyReceivesErrorFromFailingDataPreprocessor() {
         // Given
         let preprocessor = Throwing()

+ 9 - 10
Tests/ResponseTests.swift

@@ -181,6 +181,7 @@ final class ResponseStringTestCase: BaseTestCase {
 
 // MARK: -
 
+@available(*, deprecated)
 final class ResponseJSONTestCase: BaseTestCase {
     func testThatResponseJSONReturnsSuccessResultWithValidJSON() {
         // Given
@@ -378,10 +379,9 @@ final class ResponseMapTestCase: BaseTestCase {
         var response: DataResponse<String, AFError>?
 
         // When
-        AF.request(.default, parameters: ["foo": "bar"]).responseJSON { resp in
-            response = resp.map { json in
-                // json["args"]["foo"] is "bar": use this invariant to test the map function
-                ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
+        AF.request(.default, parameters: ["foo": "bar"]).responseDecodable(of: TestResponse.self) { resp in
+            response = resp.map { response in
+                response.args?["foo"] ?? "invalid"
             }
 
             expectation.fulfill()
@@ -434,10 +434,9 @@ final class ResponseTryMapTestCase: BaseTestCase {
         var response: DataResponse<String, Error>?
 
         // When
-        AF.request(.default, parameters: ["foo": "bar"]).responseJSON { resp in
-            response = resp.tryMap { json in
-                // json["args"]["foo"] is "bar": use this invariant to test the tryMap function
-                ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
+        AF.request(.default, parameters: ["foo": "bar"]).responseDecodable(of: TestResponse.self) { resp in
+            response = resp.tryMap { response in
+                response.args?["foo"] ?? "invalid"
             }
 
             expectation.fulfill()
@@ -534,10 +533,10 @@ final class ResponseMapErrorTestCase: BaseTestCase {
         let urlString = String.nonexistentDomain
         let expectation = self.expectation(description: "request should not succeed")
 
-        var response: DataResponse<Any, TestError>?
+        var response: DataResponse<TestResponse, TestError>?
 
         // When
-        AF.request(urlString).responseJSON { resp in
+        AF.request(urlString).responseDecodable(of: TestResponse.self) { resp in
             response = resp.mapError { error in
                 TestError.error(error: error)
             }

+ 1 - 1
Tests/ServerTrustEvaluatorTests.swift

@@ -1424,7 +1424,7 @@ final class StaticServerTrustAccessorTests: ServerTrustPolicyTestCase {
 
     func testThatRevocationEvaluatorCanBeCreatedStaticallyFromProtocol() {
         // Given, When, Then
-        consumeServerTrustEvaluator(.revocation())
+        consumeServerTrustEvaluator(.revocationChecking())
     }
 
     func testThatPinnedCertificatesEvaluatorCanBeCreatedStaticallyFromProtocol() {

+ 46 - 46
Tests/SessionTests.swift

@@ -825,12 +825,12 @@ final class SessionTestCase: BaseTestCase {
         let session = Session()
 
         let expectation = self.expectation(description: "request should eventually fail")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
         session.request(.basicAuth(), interceptor: handler)
             .validate()
-            .responseJSON { jsonResponse in
+            .responseDecodable(of: TestResponse.self) { jsonResponse in
                 response = jsonResponse
                 expectation.fulfill()
             }
@@ -859,7 +859,7 @@ final class SessionTestCase: BaseTestCase {
         let session = Session()
 
         let expectation = self.expectation(description: "request should eventually fail")
-        var response: DownloadResponse<Any, AFError>?
+        var response: DownloadResponse<TestResponse, AFError>?
 
         let destination: DownloadRequest.Destination = { _, _ in
             let fileURL = self.testDirectoryURL.appendingPathComponent("test-output.json")
@@ -869,7 +869,7 @@ final class SessionTestCase: BaseTestCase {
         // When
         session.download(.basicAuth(), interceptor: handler, to: destination)
             .validate()
-            .responseJSON { jsonResponse in
+            .responseDecodable(of: TestResponse.self) { jsonResponse in
                 response = jsonResponse
                 expectation.fulfill()
             }
@@ -894,14 +894,14 @@ final class SessionTestCase: BaseTestCase {
         let session = Session(interceptor: handler)
 
         let expectation = self.expectation(description: "request should eventually fail")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         let uploadData = Data("upload data".utf8)
 
         // When
         session.upload(uploadData, to: .method(.post))
             .validate()
-            .responseJSON { jsonResponse in
+            .responseDecodable(of: TestResponse.self) { jsonResponse in
                 response = jsonResponse
                 expectation.fulfill()
             }
@@ -927,12 +927,12 @@ final class SessionTestCase: BaseTestCase {
         let session = Session()
 
         let expectation = self.expectation(description: "request should eventually fail")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
         let request = session.request(.basicAuth(), interceptor: handler)
             .validate()
-            .responseJSON { jsonResponse in
+            .responseDecodable(of: TestResponse.self) { jsonResponse in
                 response = jsonResponse
                 expectation.fulfill()
             }
@@ -960,12 +960,12 @@ final class SessionTestCase: BaseTestCase {
         let session = Session(interceptor: sessionHandler)
 
         let expectation = self.expectation(description: "request should eventually fail")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
         let request = session.request(.basicAuth(), interceptor: requestHandler)
             .validate()
-            .responseJSON { jsonResponse in
+            .responseDecodable(of: TestResponse.self) { jsonResponse in
                 response = jsonResponse
                 expectation.fulfill()
             }
@@ -997,12 +997,12 @@ final class SessionTestCase: BaseTestCase {
         let session = Session(interceptor: handler)
 
         let expectation = self.expectation(description: "request should eventually succeed")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
         let request = session.request(.basicAuth())
             .validate()
-            .responseJSON { jsonResponse in
+            .responseDecodable(of: TestResponse.self) { jsonResponse in
                 response = jsonResponse
                 expectation.fulfill()
             }
@@ -1030,12 +1030,12 @@ final class SessionTestCase: BaseTestCase {
         let session = Session(interceptor: handler)
 
         let expectation = self.expectation(description: "request should eventually fail")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
         let request = session.request(.basicAuth())
             .validate()
-            .responseJSON { jsonResponse in
+            .responseDecodable(of: TestResponse.self) { jsonResponse in
                 response = jsonResponse
                 expectation.fulfill()
             }
@@ -1066,12 +1066,12 @@ final class SessionTestCase: BaseTestCase {
         let session = Session(interceptor: handler)
 
         let expectation = self.expectation(description: "request should eventually fail")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
         let request = session.request(.basicAuth())
             .validate()
-            .responseJSON { jsonResponse in
+            .responseDecodable(of: TestResponse.self) { jsonResponse in
                 response = jsonResponse
                 expectation.fulfill()
             }
@@ -1101,12 +1101,12 @@ final class SessionTestCase: BaseTestCase {
         let session = Session(interceptor: handler)
 
         let expectation = self.expectation(description: "request should eventually fail")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
         let request = session.request(.basicAuth())
             .validate()
-            .responseJSON { jsonResponse in
+            .responseDecodable(of: TestResponse.self) { jsonResponse in
                 response = jsonResponse
                 expectation.fulfill()
             }
@@ -1143,12 +1143,12 @@ final class SessionTestCase: BaseTestCase {
         let session = Session()
 
         let expectation = self.expectation(description: "request should eventually fail")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
         let request = session.request(.image(.jpeg), interceptor: handler)
             .validate()
-            .responseJSON { jsonResponse in
+            .responseDecodable(of: TestResponse.self) { jsonResponse in
                 response = jsonResponse
                 expectation.fulfill()
             }
@@ -1163,7 +1163,7 @@ final class SessionTestCase: BaseTestCase {
         XCTAssertEqual(request.retryCount, 0)
         XCTAssertEqual(response?.result.isSuccess, false)
         XCTAssertEqual(response?.error?.isResponseSerializationError, true)
-        XCTAssertEqual((response?.error?.underlyingError as? CocoaError)?.code, .propertyListReadCorrupt)
+        XCTAssertNotNil(response?.error?.underlyingError as? DecodingError)
         assert(on: session.rootQueue) {
             XCTAssertTrue(session.requestTaskMap.isEmpty)
             XCTAssertTrue(session.activeRequests.isEmpty)
@@ -1178,19 +1178,19 @@ final class SessionTestCase: BaseTestCase {
         let session = Session()
 
         let json1Expectation = expectation(description: "request should eventually fail")
-        var json1Response: DataResponse<Any, AFError>?
+        var json1Response: DataResponse<TestResponse, AFError>?
 
         let json2Expectation = expectation(description: "request should eventually fail")
-        var json2Response: DataResponse<Any, AFError>?
+        var json2Response: DataResponse<TestResponse, AFError>?
 
         // When
         let request = session.request(.image(.jpeg), interceptor: handler)
             .validate()
-            .responseJSON { response in
+            .responseDecodable(of: TestResponse.self) { response in
                 json1Response = response
                 json1Expectation.fulfill()
             }
-            .responseJSON { response in
+            .responseDecodable(of: TestResponse.self) { response in
                 json2Response = response
                 json2Expectation.fulfill()
             }
@@ -1218,7 +1218,7 @@ final class SessionTestCase: BaseTestCase {
             XCTAssertTrue(error.isRequestRetryError)
             if case let .requestRetryFailed(retryError, originalError) = error {
                 XCTAssertEqual(retryError.asAFError?.urlConvertible as? String, "/invalid/url/\(index + 1)")
-                XCTAssertEqual((originalError.asAFError?.underlyingError as? CocoaError)?.code, .propertyListReadCorrupt)
+                XCTAssertNotNil(originalError.asAFError?.underlyingError as? DecodingError)
             } else {
                 XCTFail("Error failure reason should be response serialization failure")
             }
@@ -1231,24 +1231,24 @@ final class SessionTestCase: BaseTestCase {
         let session = Session()
 
         let json1Expectation = expectation(description: "request should eventually fail")
-        var json1Response: DataResponse<Any, AFError>?
+        var json1Response: DataResponse<TestResponse, AFError>?
 
         let json2Expectation = expectation(description: "request should eventually fail")
-        var json2Response: DataResponse<Any, AFError>?
+        var json2Response: DataResponse<TestResponse, AFError>?
 
         // When
         let request = session.request(.image(.jpeg), interceptor: handler)
             .validate()
-            .responseJSON { response in
+            .responseDecodable(of: TestResponse.self) { response in
                 json1Response = response
                 json1Expectation.fulfill()
             }
-            .responseJSON { response in
+            .responseDecodable(of: TestResponse.self) { response in
                 json2Response = response
                 json2Expectation.fulfill()
             }
 
-        waitForExpectations(timeout: 10, handler: nil)
+        waitForExpectations(timeout: timeout)
 
         // Then
         XCTAssertEqual(handler.adaptCalledCount, 2)
@@ -1268,7 +1268,7 @@ final class SessionTestCase: BaseTestCase {
 
         for error in errors {
             XCTAssertTrue(error.isResponseSerializationError)
-            XCTAssertEqual((error.underlyingError as? CocoaError)?.code, .propertyListReadCorrupt)
+            XCTAssertNotNil(error.underlyingError as? DecodingError)
         }
     }
 
@@ -1286,24 +1286,24 @@ final class SessionTestCase: BaseTestCase {
         let session = Session()
 
         let json1Expectation = expectation(description: "request should eventually fail")
-        var json1Response: DataResponse<Any, AFError>?
+        var json1Response: DataResponse<TestResponse, AFError>?
 
         let json2Expectation = expectation(description: "request should eventually fail")
-        var json2Response: DataResponse<Any, AFError>?
+        var json2Response: DataResponse<TestResponse, AFError>?
 
         // When
         let request = session.request(.image(.jpeg), interceptor: handler)
             .validate()
-            .responseJSON { response in
+            .responseDecodable(of: TestResponse.self) { response in
                 json1Response = response
                 json1Expectation.fulfill()
             }
-            .responseJSON { response in
+            .responseDecodable(of: TestResponse.self) { response in
                 json2Response = response
                 json2Expectation.fulfill()
             }
 
-        waitForExpectations(timeout: 10, handler: nil)
+        waitForExpectations(timeout: timeout)
 
         // Then
         XCTAssertEqual(handler.adaptCalledCount, 2)
@@ -1341,24 +1341,24 @@ final class SessionTestCase: BaseTestCase {
         let session = Session()
 
         let json1Expectation = expectation(description: "request should eventually fail")
-        var json1Response: DownloadResponse<Any, AFError>?
+        var json1Response: DownloadResponse<TestResponse, AFError>?
 
         let json2Expectation = expectation(description: "request should eventually fail")
-        var json2Response: DownloadResponse<Any, AFError>?
+        var json2Response: DownloadResponse<TestResponse, AFError>?
 
         // When
         let request = session.download(.image(.jpeg), interceptor: handler)
             .validate()
-            .responseJSON { response in
+            .responseDecodable(of: TestResponse.self) { response in
                 json1Response = response
                 json1Expectation.fulfill()
             }
-            .responseJSON { response in
+            .responseDecodable(of: TestResponse.self) { response in
                 json2Response = response
                 json2Expectation.fulfill()
             }
 
-        waitForExpectations(timeout: 10, handler: nil)
+        waitForExpectations(timeout: timeout)
 
         // Then
         XCTAssertEqual(handler.adaptCalledCount, 2)
@@ -1416,14 +1416,14 @@ final class SessionTestCase: BaseTestCase {
         let session = Session()
 
         let expectation = self.expectation(description: "request should complete")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
         var completionCallCount = 0
 
         // When
         let request = session.request(.default, interceptor: handler)
         request.validate()
 
-        request.responseJSON { resp in
+        request.responseDecodable(of: TestResponse.self) { resp in
             request.cancel()
 
             response = resp
@@ -1455,10 +1455,10 @@ final class SessionTestCase: BaseTestCase {
         let session = Session()
 
         let expectation = self.expectation(description: "request should complete")
-        var response: DataResponse<Any, AFError>?
+        var response: DataResponse<TestResponse, AFError>?
 
         // When
-        let request = session.request(.default).responseJSON { resp in
+        let request = session.request(.default).responseDecodable(of: TestResponse.self) { resp in
             response = resp
             expectation.fulfill()
         }

+ 3 - 3
Tests/UploadTests.swift

@@ -204,7 +204,7 @@ final class UploadDataTestCase: BaseTestCase {
     func testUploadDataRequestWithProgress() {
         // Given
         let url = Endpoint.method(.post).url
-        let string = String(repeating: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ", count: 300)
+        let string = String(repeating: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ", count: 1000)
         let data = Data(string.utf8)
 
         let expectation = self.expectation(description: "Bytes upload progress should be reported: \(url)")
@@ -683,9 +683,9 @@ final class UploadMultipartFormDataTestCase: BaseTestCase {
     private func executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: Bool) {
         // Given
         let loremData1 = Data(String(repeating: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
-                                     count: 100).utf8)
+                                     count: 500).utf8)
         let loremData2 = Data(String(repeating: "Lorem ipsum dolor sit amet, nam no graeco recusabo appellantur.",
-                                     count: 100).utf8)
+                                     count: 500).utf8)
 
         let expectation = self.expectation(description: "multipart form data upload should succeed")