Firebase FireStore Library?

Right now I see support for the Real Time Database which is great. Although, I’m curious if there is support for Firebase FireStore.

Not at this time, but as with all our integrations, these are hosted within the VM (and they’re open source) so you could certainly take the current one and add support for firestore.

You’d likely get to reuse the authentication code which is the biggest complexity as I remember.

Don’t know if you’re still looking to or have figured it out but I was able to get it working somewhat. I’m not a great coder so I’m guessing this is more of a brute force attempt at it… and could be done much better… but I’m learning too!

Used the OAuth2 authentication so I don’t leave the Firestore or Firebase rules open to anyone.

Biggest issue is the Firestore wants the Authentication as a header and not as .json at the end of the URL. Needed to edit the Firebase library methods: _buildUrl() and _createAndSendRequest so that the URL is just the base + path and that an Authentication : Bearer header is added. Then create methods to do what ever you want. Your base URL is different as well: https://firestore.googleapis.com/v1/projects/" + _db + "/databases/(default)/documents in the constructor.

There some extra stuff you have to put in your path as well for firestore to see where you’re wanting to get data from. Reference the Firestore Rest API.

This is my quick class that I extended. You need to reuse the setAuthProvider after creating the object. Same parameters as the examples show for Firebase but add into the scope “https://www.googleapis.com/auth/datastore

Like I said… brute force/messy. :smiley:

class Firestore extends Firebase {
    constructor(db, auth = null, domain = "firebaseio.com", debug = true) {
        _debug = debug;

        _db = db;
        _domain = domain;
        _baseUrl = "https://firestore.googleapis.com/v1/projects/" + _db + "/databases/(default)/documents";
        _auth = auth;
        _authType = FIREBASE_AUTH_TYPE.LEGACY_TOKEN;

        _bufferedInput = "";

        _data = {};

        _callbacks = {};

        _promiseIncluded = ("Promise" in getroottable());
        _backOffTimer = FB_DEFAULT_BACK_OFF_TIMEOUT_SEC;
    }

    /************ Private Functions (DO NOT CALL FUNCTIONS BELOW) ************/
    // Builds a url to send a request to
    function _buildUrl(path, authToken, uriParams = null) {
        // Normalise the /'s
        // _baseUrl = <_baseUrl>
        // path = <path>
        if (_baseUrl.len() > 0 && _baseUrl[_baseUrl.len()-1] == '/') _baseUrl = _baseUrl.slice(0, -1);
        if (path.len() > 0 && path[0] == '/') path = path.slice(1);

        // Firestore, removed the .json ending
        local url = _baseUrl + "/" + path;

        if(typeof(uriParams) != "table") uriParams = {}

        local quoteWrappedKeys = [
            "startAt",
            "endAt" ,
            "equalTo",
            "orderBy"
        ]

        foreach(key, value in uriParams){
            if(quoteWrappedKeys.find(key) != null && typeof(value) == "string") uriParams[key] = "\"" + value + "\""
        }

        //TODO: Right now we aren't doing any kind of checking on the uriParams - we are trusting that Firebase will throw errors as necessary

        // Use instance values if these keys aren't provided
        if (!("ns" in uriParams)) uriParams.ns <- _db;
        // Removed the auth addition to the uriParams table.
        // ns isn't used either it looks like but left it there just in case

        return url;
    }

    function _createAndSendRequest(method, path, uriParams, headers, body, onSuccess, onError) {
        _acquireAuthToken(function (token, error) {
            if (error) {
                onError(error);
            } else {
                local url = _buildUrl(path, token, uriParams);

                // Firestore required header for auth. add it here from the passed in token for OAuth
                // I don't know if this works with anything but OAuth...
                headers.Authorization <- "Bearer " + token;

                local request = http.request(method, url, headers, body ? body : "");
                request.setvalidation(VALIDATE_USING_SYSTEM_CA_CERTS);
                request.sendasync(_createResponseHandler(onSuccess, onError).bindenv(this));
            }
        }.bindenv(this));
    }

    function getDocument(path, uriParams = null, callback = null) {
        if (typeof uriParams == "function") {
            callback = uriParams;
            uriParams = null;
        }
        return _processRequest("GET", path, uriParams, _defaultHeaders, null, callback);
    }
}