Webservice class with parser using generics I'm currently building a small web stack in swift for use in my iOS apps. It consists of multiple components and I want to make it resource specific;
To that end, I have a WebService class composed of two parts; a part that handles the request logic, and a part that handles the parsing.

The catch here is that the parsing is defined by a ParserType protocol with an associated type ModelType, which needs to be specified by the adopter. It parses Any? to that ModelType:

public protocol ParserType {

    associatedtype ModelType

    func parse(_ data: Any?) throws -&gt; ModelType
}


This is no problem on its own; a concrete parser could look like this (just forgive me the force casting here):

public class SimpleJSONParser&lt;T: Codable&gt;: ParserType {

    public typealias ModelType = T
    private let jsonDecoder: JSONDecoder

    public init(jsonDecoder: JSONDecoder = JSONDecoder()) {
        self.jsonDecoder = jsonDecoder
    }


    open func parse(_ data: Any?) throws -&gt; T {
        let response = try jsonDecoder.decode(T.self, from: data as! Data)
        return response
    }
}


Now we have a concrete JSON parser that tries to parse Any? to T. That's cool, so we want to inject it into WebService, so it can be used. It looks like this:

public class WebService&lt;ModelType, Parser: ParserType&gt; {

    public typealias ModelType = Parser.ModelType
    public typealias WebServiceCompletion = (Result&lt;ModelType&gt;) -&gt; Void

    private let endpoint: String
    private let parser: Parser
    private let transport: ServiceTransport

    public init(transport: ServiceTransport, endpoint: String, parser: Parser) {
        self.transport = transport
        self.endpoint = endpoint
        self.parser = parser
    }

    @discardableResult
    open func fetch(path: String? = nil, headers: [String: String]? = nil, parameters: [String: String]? = nil, autoResumeTask: Bool = true, completion: @escaping WebServiceCompletion) -&gt; ServiceTransportTask {

        let endpointToUse = endpoint + (path ?? "")

        let task = transport.perform(action: .get, path: endpointToUse, parameters: parameters, headers: headers, body: nil)
                .completion { response in
                    switch response {
                    case .failure(let error):
                        completion(.failure(error))
                    case .success(let data):
                        do {
                            let result: ModelType = try self.parser.parse(data)
                            completion(.success(result))
                        } catch let error {
                            completion(.failure(error))
                        }
                    }
                }

        if autoResumeTask {
            task.resume()
        }

        return task
    }
}


The issue I have is that when I want to use this, I have to specify to the WebService that I want to use it for a type CategoryArray for example, with a parser that parses JSON to CategoryArray, i.e. JSONParser&lt;CategoryArray&gt;, and then also inject such a parser into the WebService:

let transport = HTTPTransport(baseURL: URL(string: baseURLString)!)
let parser = JSONParser&lt;CategoryArray&gt;()
let webService: WebService&lt;CategoryArray, JSONParser&lt;CategoryArray&gt;&gt; webService = WebService(transport: transport, endpoint: endPoint, parser: parser)


It feels a bit weird to me in the sense that I have to define the model type to use in both WebService and Parser, and also define the parser type. 

Is my approach too generic, or can I factor out something here?
Turns out I can just use the generic ModelType defined in the ParserType, and I don't need the same generic parameter in WebService;

public class WebService&lt;Parser: ParserType&gt; {
...


The typealias is just for convenience, to not type ParserType.ModelType everywhere but just ModelType.

Results in this call site: 

let transport = HTTPTransport(baseURL: URL(string: baseURLString)!)
let parser = JSONParser&lt;CategoryArray&gt;()
let webService: WebService&lt;JSONParser&lt;CategoryArray&gt;&gt; webService = WebService(transport: transport, endpoint: endPoint, parser: parser)


(And because of type inference, the last line can be reduced to let webService = WebService(transport: transport, endpoint: endPoint, parser: parser) which is neat)