Originally Alamofire provides both response and request as a part of Response structure. It helps with debugging and logging of incidents. Current implementation of Moya.Response has only response NSURLResponse (instead of NSHTTPURLResponse in Alamofire) and no request information at all. With such approach when error happened there is no way to find for which request it happened. There is also no way to find header fields from NSURLResponse. With all being said what would be a recommended way of analyzing and logging Moya Errors?
To debug using Moya, I generally take advantage of the NetworkLoggerPlugin. See the Providers documentation.
Yeah, basically you pass the plugins in init of your provider, the same as closures, manager etc. For example something like:
MoyaProvider<GitHub>(plugins: [NetworkLoggerPlugin()])
NetworkLoggerPlugin does not have correlation capabilities. It seems like logging strategy now "all or nothing" while I have a particular need in mind which I believe is common. When error happened I would like to log both response with an error and request that caused it. Does it look like a valid problem?
I've written a whitelist/blacklist logger plugin. It's not elegant (which is why it's not in Moya 馃槢 ) but it works: https://github.com/artsy/eidolon/blob/master/Kiosk/App/Networking/NetworkLogger.swift
Would it be a natural thing to return back correlation of request & response into Moya result? Why in Miya.swift on line 207 of Alamofire response, NSURLRequest just discarded, while the rest is propagated as result? It is common feature of networking libraries. It was in Alamofire, MKNetworkingKit etc as well as for libraries on other platforms. As I am not really familiar with details of some architecture decisions It would be interesting to understand what was a decision process for removing this feature from Moya.
I can think of a few ways to accomplish what you're after.
plugins.forEach { $0.didReceiveRequest(request, result: result, target: target) }. Again a fork, but such a subtle difference that this would probably be easier to maintain. And the debugging would be off on its own, in a plugin, which is nice.provider.request(.Zen) { result in
let request = Api.Zen.urlRequest
...
Better yet would be to wrap this in a networking layer, and then you can send the request back in a custom completion block:
class Network {
static let provider = MoyaProvider<MyService>()
static func request(endpoint: MyService, completion: (NSURLRequest, Result) -> Void) {
provider.request(endpoint) { result in completion(endpoint.urlRequest, result) }
}
}
Yeah that would be awesome to have request printed such as:
curl -X GET blablabla
You can now get curl commands logged using the included network activity plugin.
@colinta recreating URL requests is not the same as getting a reference to the one that were sent. There could be various random identifiers attached etc, so the question to trace an exact request sent. Somehow "hard way" looks most logical one, which is very unfortunate. Thanks.
@nikita-leonov what do you think, has this issue been addressed to your satisfaction? If not, what are the next steps?
@ashfurrow as for today we do not have a good solution. The only elegant solution is option 1 suggested by @colinta, but maintaining an own fork of Moya at the current stage of our project is killing. Having correlation logging in the plugin does not work as well since such option missing a context of the call and many other benefits of having request together in response in a place of request initialization.
Recreating a call when needed does not work, since as I mentioned it missing parameters uniquely generated for the response.
Do you think re-introducing request & response correlation, that was initially available in AFNetworking would be accepted as PR into Moya? I would be happy to work on it.
I'd be happy to review a PR, I'm not sure what request/response correlation would look like so I can't say for sure if it'd be accepted. Could you explain your implementation idea?
@ashfurrow I provided PR. Understand a point about "no guarantees on accepting it", no worries. I am happy to discuss and provide changes if you think something is not in line with grand-plan of Moya.
PR is merged! Are there any next steps on this issue?
Closing this for now, as it seems this has been resolved by merging the PR. Please reopen if there's anything else that needs discussing! :)
@BasThomas @ashfurrow
Actually merging PR is not enough to get request information when "request" method is failed.
MoyaProvider<NetworkAPI>().request(.getList) { (result) in
switch result {
case .success(let response)
break
case .failure(let moyaError)
// We can not get any request information here
// Because Response that has request information object not available here
}
}
Alamofire has custom struct that has request property, in this way we can grab request information in response closure like below
Alamofire.request(url,
method: method,
parameters: parameters,
encoding: encoding,
headers: headers)
.responseJSON { (dataResponse) in
if let request = dataResponse.request {
...
}
}
public struct DataResponse<Value> {
/// The URL request sent to the server.
public let request: URLRequest?
...
}
public typealias Completion = (_ result: Result<Moya.Response, MoyaError>) -> Void
1- Add request property to compilation as a new parameter,
2- Create wrapper struct for Result<Moya.Response, MoyaError> like Alamofire did.
public struct MoyaResponse<Value, Error> {
/// The URL request sent to the server.
public let request: URLRequest?
/// The result of response serialization.
public let result: Result<Value, Error>
/// Returns the associated value of the result if it is a success, `nil` otherwise.
public var value: Value? { return result.value }
/// Returns the associated error value if the result if it is a failure, `nil` otherwise.
public var error: Error? { return result.error }
public init(request: URLRequest?,
result: Result<Value, MoyaError>) {
self.request = request
self.result = result
}
Most helpful comment
Would it be a natural thing to return back correlation of request & response into Moya result? Why in Miya.swift on line 207 of Alamofire response, NSURLRequest just discarded, while the rest is propagated as result? It is common feature of networking libraries. It was in Alamofire, MKNetworkingKit etc as well as for libraries on other platforms. As I am not really familiar with details of some architecture decisions It would be interesting to understand what was a decision process for removing this feature from Moya.