Is there a way to track an instance in Node without passing it around everywhere? - node.js

I have a singleton logger file. When a request comes into Express, I use middleware to set the request ID.
// Relevant parts of server.js
import express from 'express';
import requestIdMiddleware from './request-id-middleware';
const app = express();
app.use(requestIdMiddleware);
--
// Relevant parts of request-id-middleware.js
const uuid = require('uuid/v4');
const { setRequestId } = require('./logger');
module.exports = function(req, res, next) {
const id = uuid();
req.id = id;
// This sets a static variable on the plain logger object
setRequestId(id);
next();
};
--
// Relevant parts of logger.js
module.exports = {
request_id: null,
setRequestId: id => {
this.request_id = id;
},
log: message => {
// sends a log out using this.request_id, which is shared by all users of the server
}
}
Using the plain object now means everyone is sharing the same value. So despite each request calling setRequestId, it means if the first request takes longer than the second, it may use the second request's ID when referencing logger's value.
It seems I would need to make the logger a class instead of a plain object, instantiate it in my request middleware, and then pass the instance through to ensure unique request IDs across multiple calls from same request. Although unlikely, hoping to find a way around needing to pass a variable down into anything I want to log from.

Related

How to use i18next in serverless node js?

I am using Node JS Azure functions. I am trying to internationalize the error messages returned by the functions with i18next. I could find examples with express or plain node server. In these cases middleware pattern can be used.
But for functions, I need a way to call i18next.t('key') with probably a language parameter which I am not able to find. Calling i18next.changeLanguage() before every call to i18next.t('key') doesn't seem practical.
My skeleton code is as follows
const i18next = require("i18next");
const backend = require("i18next-node-fs-backend");
const options = {
// path where resources get loaded from
loadPath: '../locales/{{lng}}/{{ns}}.json',
// path to post missing resources
addPath: '../locales/{{lng}}/{{ns}}.missing.json',
// jsonIndent to use when storing json files
jsonIndent: 4
};
i18next.use(backend).init(options);
exports.getString = (key, lang) => {
//i18next.changeLanguage(lang,
return i18next.t(key);
}
It is possible to fetch translations without doing changeLanguage each time?
As pointed out in the comments you need to call the i18next.changeLanguage(lang) function whenever the language needs to be defined or changed.
You can take a look to the documentation here.
The code could look like this
const i18next = require('i18next')
const backend = require('i18next-node-fs-backend')
const options = {
// path where resources get loaded from
loadPath: '../locales/{{lng}}/{{ns}}.json',
// path to post missing resources
addPath: '../locales/{{lng}}/{{ns}}.missing.json',
// jsonIndent to use when storing json files
jsonIndent: 4
}
i18next.use(backend).init(options)
exports.getString = (key, lang) => {
return i18next
.changeLanguage(lang)
.then((t) => {
t(key) // -> same as i18next.t
})
}

How to properly use dataloaders across multiple users?

In caching per request the following example is given that shows how to use dataloaders in express.
function createLoaders(authToken) {
return {
users: new DataLoader(ids => genUsers(authToken, ids)),
}
}
var app = express()
app.get('/', function(req, res) {
var authToken = authenticateUser(req)
var loaders = createLoaders(authToken)
res.send(renderPage(req, loaders))
})
app.listen()
I'm confused about passing authToken to genUsers batch function. How should a batch function be composed to use authToken and to return each user corresponding results??
What the example is saying that genUsers should use the credentials of the current request's user (identified by their auth token) to ensure they can only fetch data that they're allowed to see. Essentially, the loader gets initialised at the start of the request, and then discarded at the end, and never recycled between requests.

handling Postbacks From other website to My website

Im using SuperRewards (SR) To make Coin transaction for users in my website,maybe you are familiar with SR.
Whenever a transaction happens SuperRewards sends a postback (Post Request) to my server containing information about the transaction and coins etc...
So my question is how to handle Postbacks or Post request ( i really dont know the diffrence ) from other website to my server USing Nodejs Express ?
Picture 1 App testing
picture 2 app Testing
Code
You would handle it like any other request coming to your Express app. Since it's a GET request, you would have a GET route defined.
According to section Fields and Formats, you get back quite a few query strings. Knowing that we can do the following:
app.get('/super-rewards', async (req, res) => {
// `new` is a reserved keyword, so we can't use `new` as a variable name.
const newCurrency = req.query['new']
const {
id,
uid,
oid,
total,
sig
} = req.query
})
Additionally, the documentation states that sig should match the MD5 hash of your secret key, if I'm understanding that correctly. So a full example would be something like:
const crypto = require('crypto')
const express = require('express')
const app = express()
app.get('/super-rewards', async (req, res) => {
// `new` is a reserved keyword, so we can't use `new` as a variable name.
const newCurrency = req.query['new']
const {
id,
uid,
oid,
total,
sig
} = req.query
const secretHash = crypto.createHash('md5').update(process.env.SECRET_KEY).digest('hex')
if (secretHash !== sig) {
throw new Error('Invalid transaction')
}
})
Aside, it is a GET request because the documentation clearly states that:
Postbacks are sent from our server to yours using a HTTP GET request (...)
I contacted the support team and they told me i must use a public domain not Local host that s why it wasnt working so the problem is solved and thank you for your time :)

NodeJS Express Dependency Injection and Database Connections

Coming from a non Node background, my first instinct is to define my service as such
MyService.js
module.exports = new function(dbConnection)
{
// service uses the db
}
Now, I want one open db connection per request, so I define in middleware:
res.locals.db = openDbConnection();
And in some consuming Express api code:
api.js
var MyService = require(./services/MyService')
...
router.get('/foo/:id?', function (req, res) {
var service = new MyService(res.locals.db);
});
Now, being that Node's preferred method of dependency injection is via the require(...) statement, it seems that I shouldn't be using the constructor of MyService for injection of the db.
So let's say I want to have
var db = require('db');
at the top of MyService and then use somehow like db.current....but how would I tie the db to the current res.locals object now that db is a module itself? What's a recommended way of handling this kind of thin in Node?
Updated Answer: 05/02/15
If you want to attach a DB connection to each request object, then use that connection in your service, the connection will have to be passed to myService some how. The example below shows one way of doing that. If we try to use db.current or something to that effect, we'll be storing state in our DB module. In my experience, that will lead to trouble.
Alternatively, I lay out the approach I've used (and still use) in this previous answer. What this means for this example is the following:
// api.js
var MyService = require(./services/MyService')
...
router.get('/foo/:id?', function (req, res) {
MyService.performTask(req.params.id);
});
// MyService.js
var db = require('db');
module.exports = {
performTask: function(id)
{
var connection = db.getOpenConnection();
// Do whatever you want with the connection.
}
}
With this approach, we've decoupled the DB module from the api/app/router modules and only the module that actually uses it will know it exists.
Previous Answer: 05/01/15
What you're talking about could be done using an express middleware. Here's what it might look like:
var db = require('db');
// Attach a DB connection to each request coming in
router.use(req, res, next){
req.locals.db = db.getOpenConnection();
next();
}
// Later on..
router.get('/foo/:id?', function (req, res) {
// We should now have something attached to res.locals.db!
var service = new MyService(res.locals.db);
});
I personally have never seen something like new MyService before in express applications. That doesn't mean it can't be done, but you might consider an approach like this
// router.js
var MyService = require('MyService');
router.get('/foo/:id?', function (req, res) {
MyService.foo(res.locals.db);
});
// MyService.js
module.exports.foo(connection){
// I have a connection!
}

Using node-validator to validate multiple properties at once

I'm building a Node.js proxy with the intent of handling a single POST request and redirecting the payload to two separate endpoints.
Let's say my JSON payload is:
{
"owner":"0ce856fa-f17f-11e2-9062-9b7910849bf4",
"comment":"My super cool comment!",
"photo":"0928536a-53c4-11e3-ba86-4b026f27c637"
}
I need to validate this payload on the proxy endpoint before I send it off; each of these three properties must exist, and both owner and photo must match the regex below. If they don't pass validation, I need to handle the error(s) and return a message back to the user with an appropriate error code.
I've set up a basic Node.js instance with Express and Validator like so in order to accomplish this:
var url = require('url');
var request = require('request');
var express = require('express');
var check = require('validator').check,
sanitize = require('validator').sanitize;
var app = express();
app.use(express.json());
app.use(express.urlencoded());
app.all('*', function(req, res){
if (req.method == "POST")
{
try {
check(req.body.owner, {
is: "<owner> property of type [uuid] is required"
}).is(/\w{8}(?:-\w{4}){3}-\w{12}?/);
} catch (e) {
console.log(e);
res.json({"result":"failed","message":"Your payload didn't pass validation"});
}
}
});
app.listen(9000, function() {
console.log("Server initialized on port 9000");
});
The problem: this is all fine and dandy and works great for a single validation (in this case owner), but e on catch doesn't contain any details about the property that failed validation -- if I set up multiple checks, I'd have no idea which one failed or why.
How can I set up a series of checks and retrieve the custom message I've configured? It talks about using req.onValidationError in the Validator readme, but that looks to be front-end validation, I'm not clear how (if possible) to integrate that up with the server-side code.
try express-validator which provides errors handling like:
var errors = req.validationErrors();
Update, using express-validator:
Per #shawnzhu's suggestion, I implemented express-validator instead; it took a bit of tweaking to get it working with express+connect 3.0, but given it's handling of node-validator errors, it looks like the best way to go (validating headers notwithstanding).
var express = require('express'),
expressValidator = require('express-validator');
var app = express();
app.use(express.json());
app.use(express.urlencoded());
app.use(expressValidator());
req.checkBody("owner", "<owner> property of type [uuid] is required; " + req.body.owner + " is invalid.").is(uuidRegex);
req.checkBody("photo", "<photo> property of type [uuid] is required; " + req.body.owner + " is invalid.").is(uuidRegex);
req.checkBody("comment", "<comment> property can't be empty").notNull().notEmpty();
req.sanitize("comment").trim();
var errors = req.validationErrors();
if (errors)
{
res.json({"result":"failed","errors":errors});
return;
}
To get it working just with node-validator:
It was the inline message validation that was causing problems:
try {
check(req.body.owner, "<owner> property of type [uuid] is required").is(/\w{8}(?:-\w{4}){3}-\w{12}?/);
check(req.body.photo, "<photo> property of type [uuid] is required").is(/\w{8}(?:-\w{4}){3}-\w{12}?/);
check(req.body.comment, "<comment> property can't be empty").notNull().notEmpty();
} catch (e) {
res.json({"result":"failed","message":e.message});
}
This does the job, and validates each property based on the criteria.

Resources