I have a Node REST API using Express and JavaScript. I created a Database class that is able to connect, disconnect and execute the queries. My app.js (the entry file) creates an instance database of this and launches the express server. On requests I have the following flow:
requests call the middleware functions and finally the controller
the controller calls some other classes and passes in the data
Lastly these classes call the query files to access the database
The query files themselves need to access the instance of the database class. They can call the query function and pass in their prepared statement. I am not sure how to transport the instance database from my app.js (entry file) all the way to those query files.
I found multiple solutions:
using global variables
add the instance to the request object
add the instance to the response locals
add the instance to the app locals
What is the best way/practice to transport variables from one file to the whole application?
Use service architecture or dependency injection.
Service architecture Way:
Make a directory structure like this:
root (directory)
|
|-->app.js
|-->controllers (directory)
|-->services (directory)
|
|-> DatabaseService.js
|-> XYZService.js
|-> index.js
Now in your index.js file require the service classes and export the instances of those classes, like so:
var Database = require('./DatabaseService')
var XYZ = require('./XYZService')
module.exports = {
database: new Database(),
xyz: new XYZ()
}
Now, require these services wherever you want in your code, like so:
// SomeController.js
var database = require('../services').database
...
// DO WHATEVER YOU WANT WITH 'database' variable
...
Dependency Injection Way:
I'm assuming you are using express routes. Do a dependency injection by wrapping your route-controller inside a lambda function, like so:
api.get('/user/:id', function (req, res) { // <-- wrapping
var database = new Database()
return yourRouteController(req, res, database) // <-- Inject your database instance here
})
PS I personally prefer the Service way as it's more modular and readable.
The only other solution I've seen for something like this is using dependency injection. It's still using the global variable but instead of tossing it down the line from one class to the other, you could call up that particular instance of your db connection at any point while your app is runnning.
Related
I want to create a sequelize DB connection in my index.js file and then "pass" it to whichever model is being CRUDed. Is this possible in NodeJS and how?
index.js
const { Sequelize, DataTypes, QueryTypes, Model } = require('#sequelize/core');
const sequelize= require('./config/db'); //Here the DB connection is being exported
Then the router is called which calls the Controller which then requires the Model class below...
modelName.js
class ModelName extends Model {}
ModelName.init {
fields.....
sequelize //This was initialized in 'index.js' and not in this file!
}
When I try this out, I get 'Model is not defined' and 'sequelize is not defined' errors.....I am completely new to nodeJS :)
You need to define model registration functions in model modules and then use them in index.js to register all models with already created Sequelize instance.
See my other answer here to learn how to do it
My simplified server code looks like below.
server.ts
import google from "googleapis";
const androidPublisher = google.androidpublisher("v3");
app.use('something', function(req, res, n){
...
})
...(only one of the dozens of other methods use androidPublisher)
I am importing googleapis library in order to setup androidpublisher variable. However, this googleapis library is big and it takes 400ms~700ms to fully import file, when it takes 10ms~30ms to import other library files.
Because my environment is serverless architecture (firebase functions), AND because approximately 1 out of 100 requests actually need androidPublisher, I want to take advantage of dynamic import to import googleapis when it is necessary. Otherwise, above setup actually adds 400ms/700ms latency to every request that spins up new serverless instance, even when androidPublisher is not needed.
So I have made changes like below.
server.ts
let androidPublisherInstance:any;
async function getAndroidPublisher() {
const googleapis = await import("googleapis");
if (androidPublisherInstance === undefined) {
const ap = googleapis.google.androidpublisher("v3");
androidPublisherInstance = ap;
}
return androidPublisherInstance;
}
...(one of methods use getAndroidPublisher() to get androidPublisher instance)
with above setup where I am using global variable & helper function to initialize androidPublisher only when needed. This works as intended and 400ms~700ms latency gets added when androidPublisher is needed for the first time. However, I ended up with type of androidPublisherInstance to be any. I couldn't correctly define the type because type definition is available inside of googleapis and that is residing inside of getAndroidPublisher function.
Thus, I lose all benefit of using typescript and have to play guess games while using methods/properties when I use androidPublisherInstance.
And I think I must use global variable, because I do not want to initialize androidPublisher multiple times (googleapis.google.androidpublisher("v3")) whenever a function calls getAndroidPublisher()
Am I missing something? Is there a way to use dynamic import & let client to be initialized only once without needing to use global variable?
You can just import the type. As long as you use it only in type definitions, not in value expressions, the compiled JavaScript will never load the module:
import { androidpublisher_v3 } from "googleapis";
let androidpublisher: androidpublisher_v3 | undefined;
Alternatively, to make sure you don't accidentally reference it in the wrong place, use only import types:
let androidpublisher: import("googleapis").androidpublisher_v3 | undefined;
I am currently developing a web application where we are using the Model View Controller method for organizing our information and code. In our case we are combining the View and Controller into one Javascript file and the Model is separate.
My question comes here. I've got prototype objects in my model, but I want to instantiate instances of these objects in my viewcontroller Javascript file. How do I get them talking to each other?
There are some ways to achieve that. Today, the simplest one would be:
<script src='model.js'></script>
<script src='view-controller.js'></script>
So, since your model.js will be loaded first, you can use it inside the view/controller.
Another way is by using modules. The most used today is RequireJS. E.g:
require(['model'], function(model) {
// This function is called when model.js is loaded.
// If model.js calls define(), then this function is not fired until
// model's dependencies have loaded, and the model argument will hold
// the module value for model.js.
});
ECMAScript 6 (the next version of Javascript), will have native modules, so you'll be able to do:
import * as model from './model'
var x = model.variable; // etc
You might also want to look into using Browserify if you are familiar with Node and RequireJS as you an also use NPM modules in the front-end.
http://browserify.org/
Browserify allows you to export your JS code from one file and require it in another (simplified idea).
file 1: myfunc.js
var myFunc = function(){
console.log("I'm an exported function that's in another file");
};
module.exports = myFunc;
file 2: app.js
var myFunc = require('./myfunc.js');
myFunc(): // logs "I'm an exported function that's in another file"
my routes are defined in an external folder
./routes
here's the way i define the routes in my server.js file
app.get('/', routes.index);
app.post('/validation', register.valid);
the register.valid module, which is originally written in
./routes/validation.js
is responsible for creating a new user account and register it into a database (MongoDB).
How can i access an object from server.js in validation.js ? First, i thought declaring the object before defining my routes would resolve the case, but actually it doesn't seem to be the solution.
I'm assuming your current code already does work (that is, you receive the posted data), but you need access to another object from validation.js.
If your code works, then you probably have this line in server.js:
var register = require('./routes/validation');
And you need acess to the variable obj in the validation module. You could have a function inside the validation module:
var foo;
exports.configure = function(obj) {
foo = obj;
}
The exports mean the variable configure will be accessible to modules which "require" the validation module. This way you can do, inside the server.js module:
register.configure(obj);
app.post('/validation', register.valid);
The exact configuration of this will depend on what you are actually trying to accomplish. Sometimes, for example, it's good to have a database object stored in a global variable.
Generally in this kind of structure server.js will create the app object and then pass that to individual routes modules via a function. I do it by having each router module export a single function like this:
//routes/validation.js
function setup(app) {
app.get(....blah
app.post(....blah
}
module.exports = setup;
Then I tie that together in server.js like this:
//server.js
var express = require('express');
var app = express();
require('./routes/validation')(app);
See also my express_code_structure sample project for other code organization tips.
I have an Express.js Node web app. Inside my app.js, I generate a string during app initialization:
// app.js
var mongourl = /* based on process.env.VCAP_SERVICES constant */;
Now, I have a script that I load into app.js via require():
// app.js
var db = require('./db');
This script needs to use the mongourl variable defined in my app.js. What would be a good approach to perform this. I have found that I can just set the string as a process.env value, e.g.
// app.js
process.env.mongourl = /* creating the string */;
which then can be accessed in db.js via process.evn.mongourl but I'm not sure if this is a good pattern.
// in db.js you could require an app config.js file
var config = require('config');
// then access via config.db.url
// or you can pass stuff to modules
var db = require('./db')(mongourl);
// or in app.js use app.set()
app.set('mongourl', mongourl);
// then wherever you need it: app.get('mongourl')
I'm not sure if this is a good pattern
It isn't, you just pollute the global object that doesn't belong to you. Consider using a namespace, at least.
A more idiomatic approach would be to create a constructor function for the db connection which takes the string.
It doesn't have to be an actual constructor you could just add
var dburl;
exports.init = function(param) {
dburl = param:
}
Environmental variables aren't meant for that really as they are global and can be seen (and collide with) other modules. Setting it explicitly means it's local and you have much more explicit control of how it's defined if you need it async.