Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Response serialization #18

Closed
DenTelezhkin opened this issue Sep 21, 2016 · 2 comments
Closed

Response serialization #18

DenTelezhkin opened this issue Sep 21, 2016 · 2 comments
Assignees
Milestone

Comments

@DenTelezhkin
Copy link
Member

Response serialization for TRON 2.0.0 has undergone significant changes, and is influencing experience with TRON.framework in a lot of ways. In this issue we wanted to highlight our goals and current ideas for response serialization.

Previously, ResponseParseable protocol looked like this:

public protocol ResponseParseable {
    init(data: NSData) throws
}

This approach allowed us to put ResponseParseable generic restriction on APIRequest, and gather information about how a model needs to be parsed, directly from a model type. However, it has major flows. First of, you can't create factory parser, that creates subclasses from a model. Second, you can't create protocol, that has several models conforming to it, and parse response to several model types. And third, you are forced to use a constructor, which is problematic for example for CoreData objects, that are not created using a constructor, but instead a created using a static method.

Now, in TRON 2.0.0-beta.2, we are trying a different approach, here's how response serialization protocol looks now:

public protocol Parseable {
    associatedtype ModelType

    func parse(_ data: Data) throws -> ModelType
}

And we are adding mandatory response serialization properties to each TRON request method, for example:

open func request<Model, ErrorModel>(_ path: String,
                      responseParser: @escaping APIRequest<Model,ErrorModel>.ResponseParser,
                      errorParser: @escaping APIRequest<Model,ErrorModel>.ErrorParser) -> APIRequest<Model,ErrorModel>

We are using generic typealiases to define ResponseParser closure like this:

public typealias ResponseParser = (Data) throws -> Model

This way you can directly set your own kind of parser and tweak it in any way. To maintain some form of backwards compatibility, we are adding convenience method for SwiftyJSON subspec users, that prefill response and errorParser with SwiftyJSONDecodable parsers like so:

open func request<Model: JSONDecodable, ErrorModel:JSONDecodable>(_ path: String) -> APIRequest<Model,ErrorModel>
    {
        return APIRequest(path: path, tron: self,
                          responseParser: { try JSONParser<Model>().parse($0) },
                          errorParser: { JSONErrorParser().parseError(fromRequest: $0.0, response: $0.1, data: $0.2, error: $0.3)})
    }

This is, of course, a huge change, and we want to involve community to discuss better approaches. We are releasing this form of response serialization in TRON 2.0.0-beta.2 for all of you to try it out and will be improving it towards 2.0.0 release.

@RenGate
Copy link
Contributor

RenGate commented Sep 21, 2016

Looks good. I second that.

@DenTelezhkin
Copy link
Member Author

DenTelezhkin commented Sep 24, 2016

After long thought, i decided to use Alamofire DataResponseSerializerProtocol and extend it to our needs:

public protocol ErrorHandlingDataResponseSerializerProtocol : DataResponseSerializerProtocol {
    associatedtype SerializedError
    var serializeError: (Alamofire.Result<SerializedObject>?,URLRequest?, HTTPURLResponse?, Data?, Error?) -> APIError<SerializedError> { get }
}

This allows us to do several things. First, we are able to use all request information to serialize response, not only data, that was received. Second, we are now constraining our generic Model and ErrorModel types to fit into those two protocols:

open func request<Model, ErrorModel, Serializer: ErrorHandlingDataResponseSerializerProtocol>
        (_ path: String, responseSerializer : Serializer) -> APIRequest<Model,ErrorModel>
        where Serializer.SerializedObject == Model, Serializer.SerializedError == ErrorModel
    {
        return APIRequest(path: path, tron: self, responseSerializer: responseSerializer)
    }

And third, we are now allowing to use any Alamofire custom response serializer with TRON directly just by adding some minor tweaks that specialize error type.

We are releasing this response serialization as a part of 2.0.0-beta.3 release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants