7

I have an existing Firebase application (Which was built for quick prototyping and which is now grown big, I don't intend to move because existing dependencies and also because ease of use and authentication tied up) and I am trying to build a Rest API using FeatherJS.

It seems it is really easy to work with FeathersJS if you are using a standard database (MongoDB, etc). How can I integrate Firebase with Feathers keeping the best practices in place (Service Architecture, AOP)? Can I override service in Feathers and map it to my Firebase Rest endpoint?

I created a custom service in Feathers and tried doing this :

  get(id, params) {
    return Promise.resolve(FirebaseRef.child(id).once('value'));
  }

I get the:

Converting circular structure to JSON error

Is what I am doing correct?

david
  • 2,529
  • 1
  • 34
  • 50
TJ_
  • 255
  • 3
  • 12
  • I'm also very interested if there is an elegant way of integrating Firebase with FeathersJS, the way you suggested. Therefore I'm starting a bounty. – david Oct 17 '18 at 00:17

2 Answers2

5

This worked :

return Promise.resolve(FirebaseRef.child('userId1').once('value').then(function (snap) {
          return snap.val();
        }));

I am still unsure if this is how I would best integrate Firebase with FeathersJs

TJ_
  • 255
  • 3
  • 12
  • 2
    Not too sure about the integration of Firebase with FeathersJs but surely `FirebaseRef.child(id).once('value')` returns a promise without needing to be wrapped in `Promise.resolve()`? If so, then you can write `return FirebaseRef.child('userId1').once('value').then((snap) => snap.val());` – Roamer-1888 Sep 06 '16 at 05:29
  • Hi following your method I tried doing this : FirebaseRef.push(data).then( (reference) => reference.once('value').then( (snap) => snap.val())); instead of Promise.resolve(FirebaseRef.push(data).then(function (reference) { return reference.once('value').then(function (snapshot) { return snapshot.val(); }); })); The call get's stuck after the push is done can you tell me what I am doing incorrect in chaining two calls ? – TJ_ Sep 06 '16 at 06:11
  • 1
    Flexibility in the way promise chains are constructed will allow you to "flatten" your expression to `FirebaseRef.push(data).then((reference) => reference.once('value')).then((snap) => snap.val());` - look carefully and notice that here the first `.then()` closes before the second `.then()` begins. The visual impact of doing so is much less than with indented blocky-funcs{}. – Roamer-1888 Sep 06 '16 at 08:10
  • That is cool, yes i had the second .then( inside the first, but now have changed to chain them – TJ_ Sep 06 '16 at 13:18
2

The main architectural difference between Firebase and Feathers real-time is that Firebase uses key-value observation whereas Feathers uses real-time events you automatically get when following the REST architecture. The first step would be to wrap generic Firebase operations in its own custom service which could look like this (not tested):

class FirebaseService {
  constructor(name) {
    this.name = name;
  }

  ref(id) {
    return firebase.database().ref(`${this.name}/${id}`);
  }

  async get(id) {
    const ref = await this.ref(id).once('value');

    return ref.value;
  }

  async create(data) {
    const id = firebase.database().ref().child(`/${this.name}`).push().key;

    return this.update(id, data);
  }

  async update(id, data) {
    this.ref(id).set(data);

    return this.get(id);
  }

  async remove(id) {
    const deletedEntry = await this.get(id);

    this.ref(id).remove();

    return deletedEntry;
  }
}

This will already get you a Feathers Firebase integration that automatically sends real-time events as long as you use it through the Feathers API. If Firebase gets updated outside of the service and you want to notify clients, you can use the value listeners and call update and/or patch on the service on the server:

const id = <some user id>;
firebase.database().ref(`/users/${id}`).on('value', snapshot => {
  app.service('users').update(id, snapshot.value);
});
Daff
  • 43,734
  • 9
  • 106
  • 120
  • - Firebase also positions itself as a "realtime db". What's the difference here? - Are there any downsides of your suggested approach? - An important aspect of Firebase is that it opens a direct WebSocket connection to transfer the data. In the example above the data is proxied through the Feathers server. Is it possible to instantiate some WebSocket by the Feathers Service too, that all further data is directly sent between the client & Firebase, without further Feathers Service interaction? – david Oct 27 '18 at 18:26
  • 1
    The implementation I showed doesn't have to be on a Feathers server, it will work in a Feathers client (and the direct connection) as well. The difference is that Feathers is a more open and flexible [alternative to Firebase](https://feathersjs.com/feathers-vs-firebase). You can treat Firebase like a normal database in a service like I showed but for anything more than that it really comes down to committing to one or the other if you don't want to fight both. – Daff Oct 27 '18 at 18:54
  • Feathers is intended as an API layer in front of Firebase.. This abstraction layer should hide certain things, be in charge of permission control, but provide the (realtime) power of Firebase at the same time. – david Nov 01 '18 at 13:35
  • So exposing all the API implementation to the client is not an option. – david Nov 01 '18 at 14:44
  • That's not what I said. I said it is possible if you use Feathers on the client only and have it connect to Firebase directly (instead of a Feathers server). – Daff Nov 01 '18 at 19:23