lundi 31 juillet 2017

Generic way to call Network Requests for API Client

I have provided the code for my firebase API client.

Is it smart to use generics, to initialize any entity straight from json this way?

To download lists, I needed an indicator to let me know that I'm requesting a list of entities, so I added a GETALL to my HTTPMethod enum, is this bad, and something that would be confusing to others?

I also feel like this isn't flexible because I can't get entities on a node that may be a different nested levels. Hopefully that makes sense. So this probably doesn't follow open/closed principle since I have nest my entities in firebase differently ill have to change implementation inside FirebaseAPI.

From open source code i've seen, I haven't quite seen a api client designed like this and not sure if I'm using an anti pattern or something. Any help or guidance to make this maintainable.

class FirebaseAPI {

    private let session: URLSession

    init() {

        self.session = URLSession.shared
    }

    /// Responsible for Making actual API requests & Handling response
    /// Returns an observable object that conforms to JSONable protocol.
    /// Entities that confrom to JSONable just means they can be initialized with json.
    func rx_fireRequest<Entity: JSONable>(_ endpoint: Endpoint) -> Observable<[Entity]> {

        return Observable.create { [weak self] observer in

            self?.session.dataTask(with: endpoint.request, completionHandler: { (data, response, error) in

                /// Parse response from request.
                let parsedResponse = Parser.init(data: data, response: response, error: error)

                    .parse()


                switch parsedResponse {


                case .error(let error):

                    observer.onError(error)

                    return




                case .success(let data):

                    var entities = [Entity]()

                    /// Consider edge case where a list of entities are retrieved, rather than a single entity.
                    /// Iterate through each entity and initialize.
                    /// Denoted by 'GETALL' method.
                    switch endpoint.method {

                    case .GETALL:


                        /// Key (underscored) is unique identifier for each entity, which is not needed here.
                        /// value is k/v pairs of entity attributes.
                        for (_, value) in data {

                            if let value = value as? [String: AnyObject], let entity = Entity(json: value) {

                                entities.append(entity)

                            } else {

                                observer.onError(NetworkError.initializationFailure)

                                return
                            }

                            observer.onNext(entities)

                            observer.onCompleted()

                            return
                        }



                    default:

                        if let entity = Entity(json: data) {

                        observer.onNext([entity])

                        observer.onCompleted()

                    } else {

                        observer.onError(NetworkError.initializationFailure)

                        }

                    }
                }
            })

            return Disposables.create()
        }


    }
}

Aucun commentaire:

Enregistrer un commentaire