dimanche 14 février 2021

Swift Generics Protocols: can only be used as a generic constraint problem

Input data: Working on client-server application on IOS (Swift 5.2) with GraphQL and using Apollo for networking. Without going into the details of the GraphQL and Apollo work, we have:

public protocol GraphQLOperation: class {

  associatedtype Data: GraphQLSelectionSet
  ...
}
public protocol GraphQLQuery: GraphQLOperation {}
public protocol GraphQLMutation: GraphQLOperation {}

these protocols for GraphQL operations in Apollo, GraphQLMutation for mutations, and GraphQLQuery for queries respectively. They are inherited from main GraphQLOperation with associated type which is used for return type. Mutations and Queries are generated by Apollo with code generation into final classes inherited from GraphQLQuery or GraphQLMutation with generated Data structure inherited from the GraphQLSelectionSet inside of the class. Simplified version of generated class looks like:

public final class RegisterUserMutation: GraphQLMutation {
   ...
   public struct Data: GraphQLSelectionSet { ... generated data ... }
   ...
}

For executing requests Apollo has two methods:

func perform<Mutation: GraphQLMutation>(mutation: Mutation...)
func fetch<Query: GraphQLQuery>(query: Query...)

What I need? Need own NetworkClient with ApolloClient under the hood.

Wherefore: errors handling and mapping GraphQL errors to custom errors, user token prolongation logic for all requests -> all in one place. Incapsulate network logic behind the protocol.

Accordingly, i want to have one entry point in the network client for all requests and manage it already inside.

Solution: I am trying to write Network Client with one entry point for all requests:

protocol NetworkClient {
    
    func execute<Command: NetworkCommand>(command: Command) -> Response<Command.Data>
}

Where Command looks like:

protocol NetworkCommand {
    associatedtype Operation: GraphQLOperation
    typealias Data = Operation.Data
    
    var operationType: GraphQLOperationType { get }
    func getOperation() -> Operation
    
}

protocol MutationCommand: NetworkCommand where Operation: GraphQLMutation {}
protocol QueryCommand: NetworkCommand where Operation: GraphQLQuery {}

class RegisterUserCommand: MutationCommand {
    typealias Operation = RegisterUserMutation
    
    var operationType: GraphQLOperationType = .mutation
    
    func getOperation() -> RegisterUserMutation {
        return RegisterUserMutation(birthDate: "", email: "", password: "", sex: .female, username: "")
    }
}

And the implementation looks like:

class NetworkClientImpl: NetworkClient {
    
    private let apolloClient: ApolloClient
    
    init(client: ApolloClient) {
        self.apolloClient = client
    }
    
    func execute<Command>(command: Command) -> Response<Command.Data> where Command : NetworkCommand {
        switch command.operationType {
        case .mutation:
            let mutation = command.getOperation()
            apolloClient.perform(mutation: mutation as! GraphQLMutation)
        default:
            <#code#>
        }
    }
    
    
}

**Problem: ** I am getting the error in combining Apollo request types: enter image description here

Is it possible to combine them?

Aucun commentaire:

Enregistrer un commentaire