lundi 12 juin 2017

How to setup an iOS client to interact with Firebase

There are many well known design patterns for creating RESTful clients. Because Firebase is noSQL and has a different API structure than usual ( don't make requests with url, but with a database Reference such as Database.database().reference.child(users).child(uniqueId).

How can I create a client with flexibility to make requests to different nodes AND to StorageReference which is where media is stored.

So far, I have a singleton FirebaseClient which is the only way to interact with the server. For each model that accesses data at a unique location, I created a Service layer, to do handle the nitty gritty business logic, which has gotten more complex than i'd like. I want to design in a way that is maintainable, decoupled, and adheres to SOLID principles.

Im confused as to if this approach is acceptable or what other approach there is. Ill show some code to give you an idea of my current approach. Any tip or resource is greatly appreciated.

class DatabaseClient {

private static let _shared = DatabaseClient()

static var shared: DatabaseClient {
    return _shared
}




func insert(databaseReference: DatabaseReference, data: [String: Any], handler: @escaping (_ error: FirebaseError? ) -> Void ) {

    databaseReference.setValue(data) { ( error, _ ) in

        if error != nil {

            handler(.valueAssignmentFailure)

            return
        }
    }

}





func fetch(databseReference: DatabaseReference, dataEventType: DataEventType, handler: @escaping (_ results: [String: AnyObject]?, _ error: FirebaseError?) -> Void ) -> Void {

    databseReference.observe(dataEventType, with: { (snapshot) in

        guard let snapshotData = snapshot.value as? [String: AnyObject] else {

            handler(nil, .invalidSnapshot)

            return
        }

        handler(snapshotData, nil)

    })

}

}

// MARK: - One of my Service objects. I have another for Chatroom, Message, and Images.

final class UserService {

private var databaseReference: DatabaseReference {

    return DatabaseProvider.sharedInstance.usersDatabaseReference
}


init() { }



func insert(user: User, handler: @escaping (_ error: FirebaseError?) -> Void ) {

    let userReference = databaseReference.child(user.id)

    let data: [String: Any] = [Constant.id: user.id, Constant.age: user.age]

    DatabaseClient.shared.insert(databaseReference: userReference, data: data) { (error) in
        guard error == nil else {
            handler(error)
            return
        }

    }

}




func fetchUser(id: String, handler: @escaping (_ result: User?, _ error: FirebaseError?) -> Void ) {

    let userReference = databaseReference.child(id)

    DatabaseClient.shared.fetch(databseReference: userReference, dataEventType: .value) { (data, error) in
        guard error == nil else {
            handler(nil, error)
            return
        }

        guard let data = data, let newUser = User(data: data) else {
            handler(nil, .initializationFailure)
            return
        }

        handler(newUser, nil)

    }


}




func fetchUsersNearby(user: User, handler: @escaping (_ results: [User]?, _ error: FirebaseError?) -> Void ) {

    var users: [User] = []


    databaseReference.observe(.value, with: { (snapshot) in
        guard let data = snapshot.value as? [String: AnyObject] else {
            handler(nil, .invalidSnapshot)
            return
        }

        for (_, value) in data {
            guard let values = value as? [String: AnyObject], let user = User(data: values) else {
                handler(nil, .initializationFailure)
                return
            }

            users.append(user)
        }


        ChatroomService().fetchChatrooms(handler: { (chatrooms, partnerIds, error) in
            guard error == nil else {
                handler(nil, error)
                return
            }

            let validUsers = users
                .filter { user.id != $0.id }
                .filter { user.distanceFromUser(atLocation: $0.coordinates) <= 8046.72 }
                .filter { !(partnerIds?.contains($0.id))! }


            handler(validUsers, nil)
        })
    })
}

}

Aucun commentaire:

Enregistrer un commentaire