Sachin S
Sachin S

Reputation: 196

How to dynamically bind data sources for API requests in loopback

Here is scenario wherein the different api requests have to query different databases dynamically based on the origin of the request. For instance an api request has to query users table in db1 simultaneously another api or the same api with a different origin context has to query users table from db2. This can be achieved for all routes except the default ones exposed by loopback. I need a solution to dynamically bind dataSources to the default apis exposed by loopback keeping in mind it is a single threaded application so that binding the dataSource to an api should not in anyway affect the behavior of the other apis that are parallelly being served by the application.

Upvotes: 1

Views: 1119

Answers (1)

Miroslav Bajtoš
Miroslav Bajtoš

Reputation: 10785

Disclaimer: I am a co-author and one of the current maintainers of LoopBack.

My advice is to create one LoopBack application for each database and write a custom Express middleware that will route API requests to the right LoopBack application.

To prevent interaction between these per-database application instances, it's crucial to enable undocumented "local registry" mode, where each application has its own local registry of models. (By default, LoopBack uses a global model registry.)

Please note this feature is not widely used, you may run into edge cases that don't work. You may end up debugging loopback internals and sending a pull request to fix those problems. (It has already happened for one or two users in the past, therefore most issues should be fixed by now.)

const app = loopback({localRegistry: true});

The code above will create a new LoopBack application that does not share any global state and does not have any built-in models configured (no User, AccessToken, etc.)

This works well for loopback-boot which loads exactly those built-in models that are configured in server/model-config.json. If you load models manually from code, you will probably want to pre-load all built-in models to your app. This can be achieved via loadBuiltinModels option:

const app = loopback({localRegistry: true, loadBuiltinModels: true});

Now that we know how to create an app that does not share any global state, we need to create a registry of LoopBack applications, one for each database (this can be done lazily on the first access). I'll leave this part as an exercise for the reader. The only important part is to mount loopback.rest() middleware on each per-database application, otherwise we won't be able to implement request handling later.

const app = loopback({localRegistry: true, loadBuiltinModels: true});
app.use(loopback.rest());

With the registry of LoopBack applications in place, we can write Express middleware to handle requests:

function handleApiRequest(req, res, next) {
  const app = // obtain the LoopBack application instance to use
  app(req, res, next);
}

// use the middleware in your root application, e.g.
const app = express();
app.use(cors({/*...*/});
app.use(handleApiRequest);
app.use(errorHandler({/*...*/});

Upvotes: 3

Related Questions