An easy way to make an inclusive proxy in NodeJS

Managing microservices interactions properly

Introduction

In Wolox we have a wide variety of projects we are developing. The biggest one, in which I am currently working on, it’s a marketplace app. It includes users, products, dispatch flows, finances, purchase orders and logistics modules all involving 6 API’s interacting with each other in a microservice architecture. Each of them with their own database. These APIs have different technologies- some of them are in Ruby on Rail + Postgres, others in NodeJS + MongoDB, and we are starting a new one in Java.

As you can imagine, in the web application some views require information from multiple services, and some events involve multiple validations and data modifications in different API’s. Managing these kinds of requests in frontend has its own, extremely frustrating, complexity. In order to avoid this, the architecture includes a proxy which we call BFF: Backend For Frontend.

Backend For Fronted started as a simple proxy. There was a controller for each resource of each API. Each controller made an export for each method of the resource, which was in a config file. This is how they looked:

And for each route, we also had to declare it in a routes file.

The pipe helper was a just a generic request and some logs we added in order to see headers and bodies.

The first functionality we added to BFF was the authentication. The API’s require a user token, and for this, we needed to check the users API if this token was correct. This needed to be done for almost every endpoint, so we added userAutheticatedPipe . . Later we did the same for admins.

If an endpoint needs data from different API’s, we do it in the controller.

Problems

We started facing some problems with this implementation. First of all, we were repeating the first gist of the post on every controller of our app, and every time we added a new resource, we had to add that logic. This was not maintainable at all. Any change in our serviceRoutes file will break every single endpoint and force us to change every controller (at that point we had 20 of them).

The serviceRoutes file started to be too verbose. This is arguably because it clearly reflected which resource depended every route, but adding a simple route was too much trouble in a +300 lines file.

And the biggest problem: every time someone from another backend tech had to add an endpoint, he/she asked us. Endpoints that we did not always have all the information about how they worked and what they were supposed to do, and we had to test before making the pull request. The NodeJS team of this app would not tolerate this for too much time.

The solution

Having some time left in a sprint, we started to clean our tech debt with this problem. The challenge was to stop repeating code and to make the endpoint addition in BFF easy enough for any developer to do.

The serviceRoutes file should be really simple: a config JSON and a key to add the authentication function depending on the endpoint. A piece of code to show how to add all the endpoints in the serviceRoutes with their proper method, route, and authentication. After a few attempts and code reviews, we achieved to make it work.

It is an abstraction of what we repeated on every controller. Also, we added the default method GET so we do not repeat that constant on every endpoint. For another method, we added in the methods key.

We wrote in the README of BFF the steps for adding an endpoint.

So now we have an inclusive proxy for our application! EVERY developer of our team can add an endpoint (and also may feel that he/she knows a little bit of NodeJS, although this may not be true). No more messages, cards or tickets assigned to the Node team asking to add an endpoint. And no more blocking feature because of this.