Storing JSON POST data in an array (NodeJS) - javascript

I would like to be able to post user-generated JSON objects to a NodeJS server, and store them in an array so that refreshing the page does not affect the data. I would then like to be able to read the info back into a table, so that it constantly reflects the contents of the array.
Is this possible in NodeJS? If so, could someone please give me a pointer in the right direction? I'm able to pass JSON objects (as req.body), but I don't know where to go from here.
Thanks!

As Sri suggested, you should definitively store your data array into a data base.
Use either Redis, Mongo, MySQL... It entierly depends on your data shape and the ways you will use it.
If you just neet to store temporary an array (by temporary, I mean "as long as the browsing session" or "as long as the server is up"), you can just store you data in memory.
For exemple with ExpressJs:
var express = require('express');
// in memory storage
var data = [];
var app = express()
.use(express.bodyParser())
.use(express.cookieParser())
.use(express.cookieSession({secret:'sample'}))
.post('/data', function(req, res){
// do not need session, just memmory ? use this line
// data.push(req.body);
// creates the session if needed, and store data
if (!req.session.data) {
req.session.data = [];
}
req.session.data.push(req.body);
res.send(204);
})
.get('/data', function(req, res){
res.setHeader('Content-Type', 'application/json');
// stored in session ?
res.send(req.session.data || []);
// stored in memory ?
// res.send(data);
})
.listen(80);
----- EDIT -----
To add new data and return it in a single request, just send your array in the POST response:
.post('/data', function(req, res){
// store in memory
data.push(req.body);
// send it back, updated, in json
res.setHeader('Content-Type', 'application/json');
res.send(data);
})
There is an assumption: you should call your post with an ajax call, and not a regular HTML form. Please refer to jquery.Ajax doc to get the parsed server result.

Related

How to create an express update route with multiple parameters

I want to update an attribute within a JSON object using fetch PUT. I've created a put function taking in 2 URL parameters
app.put('/trustRoutes/:id/:item', (req, res){
I am able to update the data with a single parameter but since I only want to change one value inside that object, calling put will replace the whole object with my new body.
below is what I've tried.
app.put('/trustRoutes/:id/:item', (req, res) => {
readFile(data => {
const userId = req.params['id/item'];
// have also tried const userId = req.params.id.item
data[userId] = req.body;
//write data back to file
I looked around at other examples but couldn't find any that were updating data instead of GET. If there is one I missed please let me know.
PUT requests are great for completely overwriting a resource, and is idempotent. This answer does a good job explaining idempotency. For updating a resource partially, a PATCH request is a better choice.
app.patch('/trustRoutes/:id/:item', (req, res) => {
readFile(data => {
data[userId] = req.params[id];
data[item] = req.params[item];
// A get request for this resource would now show both of the updated values
// Write file

Separate sessions of the app

I use python script to do some calculations in the backend. The proccess works as follows:
I create a list of variables by clicking on some items in the app
That list is sent to the python script and it sends back a json back
Based on that json file i display a table
Then the list of variables is ereased and I can do this again
But here is the problem, when I run this locally on c9.io, lets say I give the address of that c9.io to someone, then when that person is clicking on variables to add to that list, he adds them to the same list as I do. There are no separate lists for other people when using the app from different ip or something and therefore it gets confusing because when I send to python script I get json file with results i didnt want, but someone else did.
But then Im planning on hosting it on heroku and I wonder if it will be working differently, so when someone is using the app from there he gets his own list of the variables and it wont be shared by everyone who is using this at the same time as someone. Or is there a some way to do this specifically?
Here is the backend code for the app:
First this is the code for adding items to the list and here is the problem since anyone if doing it at the same time will be adding to the same list
var jsondata = ""
var thelist =[]
app.get("/show/:id", function (req, res) {
var id = req.params.id;
thelist.push(id)
console.log(thelist);
res.redirect('/')
});
Then the rest (so running the script and emptying the list)
app.get("/run", function(req, res) {
var pyshell = new PythonShell('script.py');
pyshell.send(JSON.stringify(thelist))
pyshell.on('message', function (message) {
// received a message sent from the Python script (a simple "print" statement)
jsondata += message
});
// end the input stream and allow the process to exit
pyshell.end(function (err) {
if (err){
throw err;
};
console.log(jsondata);
});
thelist = []
});
app.get('/data', function(req, res) {
if (jsondata == "") {
res.redirect('/')
} else {
//viewname can include or omit the filename extension
res.render("data", {data: JSON.parse(jsondata)} )
jsondata = ""}
});
So I think i need those two variables jsondata and thelist need to be somehow coded in a way that they are seprate for every unique user (as in accessing the app from different place, so the app would be run as a separate session for each user that accesses it (but also no need for registration) )

Node.js flat-cache, when to clear caches

I have a Node.js server which queries MySQL database. It serves as an api end point where it returns JSON and also backend server for my Express application where it returns the retrieved list as an object to the view.
I am looking into implementing flat-cache for increasing the response time. Below is the code snippet.
const flatCache = require('flat-cache');
var cache = flatCache.load('productsCache');
//get all products for the given customer id
router.get('/all/:customer_id', flatCacheMiddleware, function(req, res){
var customerId = req.params.customer_id;
//implemented custom handler for querying
queryHandler.queryRecordsWithParam('select * from products where idCustomers = ? order by CreatedDateTime DESC', customerId, function(err, rows){
if(err) {
res.status(500).send(err.message);
return;
}
res.status(200).send(rows);
});
});
//caching middleware
function flatCacheMiddleware(req, res, next) {
var key = '__express__' + req.originalUrl || req.url;
var cacheContent = cache.getKey(key);
if(cacheContent){
res.send(cacheContent);
} else{
res.sendResponse = res.send;
res.send = (body) => {
cache.setKey(key,body);
cache.save();
res.sendResponse(body)
}
next();
}
}
I ran the node.js server locally and the caching has indeed greatly reduced the response time.
However there are two issues I am facing that I need your help with.
Before putting that flatCacheMiddleware middleware, I received the response in JSON, now when I test, it sends me an HTML. I am not too well versed with JS strict mode (planning to learn it soon), but I am sure the answer lies in the flatCacheMiddleware function.
So what do I modify in the flatCacheMiddleware function so it would send me JSON?
I manually added a new row to the products table for that customer and when I called the end point, it still showed me the old rows. So at what point do I clear the cache?
In a web app it would ideally be when the user logs out, but if I am using this as an api endpoint (or even on webapp there is no guarantee that the user will log out the traditional way), how do I determine if new records have been added and the cache needs to be cleared.
Appreciate the help. If there are any other node.js caching related suggestions you all can give, it would be truly helpful.
I found a solution to the issue by parsing the content to JSON format.
Change line:
res.send(cacheContent);
To:
res.send(JSON.parse(cacheContent));
I created cache 'brute force' invalidation method. Calling clear method will clear both cache file and data stored in memory. You have to call it after db change. You can also try delete specified key using cache.removeKey('key');.
function clear(req, res, next) {
try {
cache.destroy()
} catch (err) {
logger.error(`cache invalidation error ${JSON.stringify(err)}`);
res.status(500).json({
'message' : 'cache invalidation error',
'error' : JSON.stringify(err)
});
} finally {
res.status(200).json({'message' : 'cache invalidated'})
}
}
Notice, that calling the cache.save() function will remove other cached API function. Change it into cache.save(true) will 'prevent the removal of non visited keys' (like mentioned in comment in the flat-cache documentation.

ExpressJS + JWT. What's the proper way to get auth data?

Let's jump to an example. I'll skip some parts like imports, exports.
I have a controller called controllers/book.js with one route:
router.get('/my-books', function(req, res) {
if(Auth.authenticated(req,res)) {
Book.getMyBooks(function(rows) {
response.operationSucceed(req, res, rows);
});
}
});
Then, in a model called models/book.js I have that function:
function getMyBooks(successCallback) {
db.query('SELECT * FROM book b WHERE b.id_user=?', [Auth.getLoggedUID()], function(rows) {
successCallback(rows);
});
}
My question is about Auth.getLoggedUID function.
Assuming that I have a JWT authentication and assuming that I have an UID in payload (is that even acceptable?), what's the best option to retrieve it? Is there any, EXCEPT passing the req every time to every function where I need auth data?
I may have a function execution inside a function, do I need to pass the req through both of them to get the user ID? Like this?:
function getBooks(req) {
getMyBooks(req);
getCriminalBooks(req);
getEvenOtherBooksByAuthor(req, authorId);
}
Honestly I wouldn't like that.
Maybe my whole concept is wrong and I should be doing things differently?
Can someone point me the right direction in scenarios like this?
You can pass UID in header and retrieve it inside your controller as:
var uid =req.header('UID');
Then pass this UID where ever you want there is no need to carryforward whole req object everywhere.
You can use a middleware function. Let's say that every request that hits your endpoints, will have a token which you should check and possibly decode it. After that, you can set the decoded content to the req object. So something like this:
app.use(function(req, res, next) {
// get the token from the request headers most likely.
// verify and decode the token
// set the decoded content to the request
var payload = ..
req.payload = payload;
});
After this you can access the payload in every single endpoint you have. So for example in some controller you can do:
app.get('/hey', function(req, res) {
var payload = req.payload;
});

sending key/value data via POST method in a REST API

I'm working on a REST API that includes a POST method to create new widgets.
The data that I need to send looks like this:
key | value
widgetnum | 12345
02:00:00_03:00:00_mtwrfsn | johndoe#myemail.com
12:00:00_15:00:00_mt | janedoe#yahoo.com
Up until now, I have been POSTing data via two keys in the BODY:
widgetnum : 12345
tc : 02:00:00_03:00:00_mtwrfsn_johndoe#myemail.com,12:00:00_15:00:00_mt_janedoe#yahoo.com
As you can see in the example above, the key "tc" actually contains information for two records, just separated by a comma.
But yesterday as i was poking around in the Postman application... I realized that I can send multiple key / value pairs. I don't know why this never clicked before. (such a noob) In any case, I realize now, I can actually do this:
widgetnum : 12345
02:00:00_03:00:00_mtwrfsn : johndoe#myemail.com
12:00:00_15:00:00_mt : janedoe#yahoo.com
Questions
Is it more efficient to change way I POST data as far as my javascript code is concerned? So for example, today, my code looks like this:
router.post('/', function(req, res, next) {
var widgetnum = req.body.widgetnum;
var tc = req.body.tc;
var tc_array = tc.split(",");
aka - I'm able to look for my data using very specific key names.
However, if I change the way I POST my data, I believe I would have to loop to find all the keys.
So something like this:
router.post('/', function(req, res, next) {
//loop through req.body object.
for (var key in req.body) {
if (req.body.hasOwnProperty(key)) {
// add some logic here to test if the key is
// widgetnum or a tc type key.
console.log(key + " -> " + req.body[key]);
}
}
res.status(200).send('ok');
return;
});
I apologize if this seems like a remedial question - it probably is.
But if it's bad form to POST multiple tc records in one key/value pair, I'm happy to change it. Perhaps there's a more efficient way to write my javascript code to find the data.
Thanks.
To send and receive key/value pair, format already exist that (almost) does the work for you. One of them is JSON, which is widely supported, especially in JavaScript.
Since you are using express already, you can add body-parser and set it to automatically parse JSON:
Data sent (POSTMan: body type: application/json, copy paste in the body.
{
"widgetnum" : 12345,
"tc" : {
"02:00:00_03:00:00_mtwrfsn": johndoe#myemail.com,
"12:00:00_15:00:00_mt": janedoe#yahoo.com
}
}
Server code:
"use strict";
const express = require('express'),
router = express.Router(),
bodyParser = require('body-parser');
router.use(bodyParser.json());
router.post('/', function(req, res, next) {
var widgetnum = req.body.widgetnum;
var tc = req.body.tc;
//No more need for tc_array
//...
}
No more need for your custom format, and req.body will be a JS object of the same form as the JSON sent, so you can do things like:
console.log(req.body.tc['02:00:00_03:00:00_mtwrfsn']); //print johndoe#myemail.com
console.log(Object.keys(req.body.tc)); //Print ['02:00:00_03:00:00_mtwrfsn', '12:00:00_15:00:00_mt']

Categories

Resources