Using RxJS Observables to mediate routes in nodejs
Are there any down sides to using RxJS on the backend


The way I see it, you get 2 benefits from RxJS


Reactivity
Streaming operations


Observables are effectively a form of event management. They run, listen to things, and execute code when something happens. They're a good way to respond when something happens in the app. However, when used in routing, your observable only lives during the duration of the request-response cycle. You lose all the benefits of a persistent event system when they're short-lived.

This leaves you with streaming operations which isn't something regular functions, promises, array methods and ternaries can't do. When observables are used this way, they effectively become what I call "fat promises". You're better off fully utilizing native constructs than using advanced constructs suboptimally.

Speaking of Node, async and await are available too, which makes life a bit easier:

// Routes
router.route('/').get(async (req, res) =&gt; {
  try {
    if (req.headers.data) {
      const res = await services.InviteService.authenticateInvite(req.headers.data)
      // respond with data
    } else {
      // respond with no header data error 
    }
  } catch (e){
    // Something else went wrong
  }

});

// Service
class InviteService  {

  constructor(models) {
    this.models = models
  }

  async findInviteById(id) {
    return this.models.Invite.findOne({ where: { inviteId: id } })
  }

  async findUserById(email) {
    return this.models.User.findOne({ where: { email: email } })
  }

  async authenticateInvite(token) {
    const payload = jwt.verify(token, appConfig.SESSION_SECRET)
    const invite = await this.findInviteById(payload.inviteId)

    if(!invite) throw new Error('Invalid Invite ID')

    return invite._isScalar ? invite : this.findUserById(payload.email)
  }
}

module.exports = InviteService;


Also, if you end up doing more comparisons after getting authenticateInvite's return value, that means authenticateInvite is not abstracting correctly. I'd expect that after I call authenticateInvite, it should be boolean. It either resolves (auth passed) or rejects (auth failed) with the error object containing the reason for failure. All business logic (and errors) should go to the service class.