so I'm making a site with node js, and I need to use localstorage, so I'm using the node-localstorage library. So basically, in one file I add data to it, and in another file I want to retrieve it. I'm not 100% sure about how to retrieve it. I know I need to use localStorage.getItem to retrieve it, but do I need to include localStorage = new LocalStorage('./scratch');? So I was wondering what the localStorage = new LocalStorage('./scratch'); did. So here is my code for adding data:
const ls = require('node-localstorage');
const express = require("express");
const router = express.Router();
router.route("/").post((req, res, next) => {
var localStorage = new ls.LocalStorage('./scratch');
if(req.body.name != undefined){
localStorage.setItem("user", req.body.name);
res.redirect('/')
}
else{
console.log("undefind")
}
});
module.exports = router;
If my question is confusing, I just want to know what var localStorage = new ls.LocalStorage('./scratch'); does.
A drop-in substitute for the browser native localStorage API that runs on node.js.
It creates an instance of the "localStorage" class, which this library provides. The constructor expects the location of the file, the scripts stores the key, value elements in.
Opinion: This looks pointless to me - I guess it fits your use case.
Related
I'm trying to do a reverse image search using googlethis on an image the user uploads. It supports reverse image searching, but only with a Google-reachable image URL. Currently, I upload the image to file.io, which deletes it after it gets downloaded.
This is the current application flow:
User POSTs file -> Server uploads file to file.io -> Google downloads the file -> Server does things with the reverse image search
However, I want to skip the middleman and have Google download files directly from the server:
User POSTs file -> Server serves file at unique URL -> Google downloads the file -> Server deletes the file -> Server does things with the reverse image search
I've looked at Serving Temporary Files with NodeJs but it just shows how to serve a file at a static endpoint. If I added a route to /unique-url, the route would stay there forever (a very slow memory leak! Probably! I'm not really sure!)
The only way I can think of is to save each file with a UUID and add a parameter: /download?id=1234567890, which would probably work, but if possible, I want to do things in memory.
So:
How do I do this using normal files?
How do I do this in-memory?
Currently working (pseudo) code:
app.post('/', (req, res) => {
const imagePath = saveImageTemporarily(req)
const tempUrl = uploadToFileIo(imagePath)
const reverseImageResults = reverseGoogleSearch(tempUrl)
deleteFile(imagePath)
doThingsWithResults(reverseImageResults).then((result) => { res.send(result) })
}
The other answer is a good one if you are able to use Redis -- it offers lots of helpful features like setting a time-to-live on entries so they're disposed of automatically. But if you can't use Redis...
The basic idea here is that you want to expose a (temporary) URL like example.com/image/123456 from which Google can download an image. You want to store the image in memory until after Google accesses it. So it sounds like there are two (related) parts to this question:
Store the file in memory temporarily
Rather than saving it to a file, why not create a Buffer holding the image data. Once you're done with it, release your reference to the buffer and the Node garbage collector will dispose of it.
let image = Buffer.from(myImageData);
// do something with the image
image = null; // the garbage collector will dispose of it now
Serve the file when Google asks for it
This is a straightforward route which determines which image to serve based on a route parameter. The query parameter you mention will work, and there's nothing wrong with that. Or you could do it as a route parameter:
app.get('/image/:id', (req, res) => {
const id = req.params.id;
res.status(200).send(/* send the image data here */);
});
Putting it all together
It might look something like this:
// store image buffers here
const imageStore = {};
app.post('/image', (req, res) => {
// get your image data here; there are a number of ways to do this,
// so I leave it up to you
const imageData = req.body;
// and generate the ID however you want
const imageId = generateUuid();
// save the image in your store
imageStore[imageId] = imageData;
// return the image ID to the client
res.status(200).send(imageId);
});
app.get('/image/:id', (req, res) => {
const imageId = req.params.id;
// I don't know off the top of my head how to correctly send an image
// like this, so I'll leave it to you to figure out. You'll also need to
// set the appropriate headers so Google recognizes that it's an image
res.status(200).send(imageStore[imageid]);
// done sending? delete it!
delete imageStore[imageId];
});
I would use REDIS for the in-memory DB, and on the server, I would transform the image to base64 to store it in Redis.
In Redis, you can also set TTL on the images.
Check my code below
import {
nanoid
} from 'nanoid'
function base64_encode(file) {
// read binary data
var bitmap = fs.readFileSync(file);
// convert binary data to base64 encoded string
return new Buffer(bitmap).toString('base64');
}
app.post('/', async(req, res) => {
const client = redisClient;
const imagePath = saveImageTemporarily(req)
//const tempUrl = uploadToFileIo(imagePath)
var base64str = base64_encode(imagePath);
const id = nanoid()
await client.set(id, JSON.stringify({
id,
image: base64str
}));
const reverseImageResults = reverseGoogleSearch(JSON.parse(await client.get(id)).image)
await client.del(id);
doThingsWithResults(reverseImageResults).then((result) => {
res.send(result)
})
}
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
})
}
I have an existing Node.js/Express app which connects to 2 separate databases, it has a MySQL DB for all the relational and a MongoDB store for the non-relational vertical data.
It uses Sequelize and Mongoose and works absolutely swimmingly.
I've been looking at Next.js today and I'm pretty impressed, one of my pet peeves with React is actually how much bootstrapping there is and how much code it takes to achieve something simple. Next.js seems to solve some of those issues for me, so I'm willing to embrace it.
First issue - Is it possible to connect Next.js to existing DB's and read their objects directly in the view?
e.g. ./server.js:
const mongoDb = mongoose.connect(configDB.url); // MongoDB connection
const models = require('./models'); // Sequelize connection
app.prepare().then(() => {
server.use((req, res, next) => {
req.mongodb = mongoDb
req.mysqldb = models
// Logging req.mysqldb/req.mongodb at this point gives the correct result.
next()
});
server.get('*', (req, res) => {
return handle(req, res)
})
})
./pages/index.js:
Index.getInitialProps = async function(req) {
console.log(req.mongodb);
console.log(req.mysqldb)
// Example of what I want: req.mysqldb.users.findAll()....... to populate collection for this view
}
When the console statements are executed in the index.js page, they are logged as undefined.
Ideally I want to use the objects/ORM layer directly in the next.js templates, I do not want to have to call my own API internally, it seems like a huge waste of resources!
Any help, greatly appreciated.
Just for future reference. getInitialProps gets passed in an object with one of the keys being req. So you're meant to do something like the following instead
// add the curly braces around req
Index.getInitialProps = async function({ req }) {
// code
}
This is known as Function Parameter Destructuring and was introduced in ES6. What this accomplishes is similar to the following code
Index.getInitialProps = async function(_ref) {
var req = _ref.req;
}
Meaning, it takes the value of req of the object that gets passed and uses that value.
Well apparently by the time the request gets to the template it has changed a bit! Namely, it is nested within another request object.
req.req.mongodb and req.req.mysqldb both work fine :).
Im trying to learn NodeJS and Express. Im using the node-localstorage package to access the localstorage. This works when using the code directly in the function like this
routes/social.js
exports.index = function(req, res)
{
if (typeof localStorage === "undefined" || localStorage === null)
{
var LocalStorage = require('node-localstorage').LocalStorage;
localStorage = new LocalStorage('./scratch');
}
localStorage.setItem('myFirstKey', 'myFirstValue');
console.log(localStorage.getItem('myFirstKey'));
res.render('social/index', {title: "Start"});
}
But I don't want to write this code over and over again in all my other functions when accessing the localstorage. I want to be able to register a helper function that I can access like
var localStorage = helpers.getLocalStorage
or something like that.
How can I do this in NodeJS? I've seen something about app.locals? But how can I access the app object in my routes?
There are many ways to do this, depending on how/where you are planning to use your helper methods. I personally prefer to set my own node_modules folder, called utils, with all the helpers and utility methods I need.
For example, assuming the following project structure:
app.js
db.js
package.json
views/
index.ejs
...
routes/
index.js
...
node_modules/
express/
...
Simply add a utils folder, under node_modules, with a index.js file containing:
function getLocalStorage(firstValue){
if (typeof localStorage === "undefined" || localStorage === null)
{
var LocalStorage = require('node-localstorage').LocalStorage;
localStorage = new LocalStorage('./scratch');
}
localStorage.setItem('myFirstKey', 'myFirstValue');
return localStorage;
}
exports.getLocalStorage = getLocalStorage;
Then, anytime you need this function, simply require the module utils:
var helpers = require('utils');
exports.index = function(req, res){
localStorage = helpers.getLocalStorage('firstValue');
res.render('social/index', {title: "Start"});
}
EDIT
As noted by Sean in the comments, this approach works as long as you name your node_modules folder with a name different from Node's core modules. This is because:
Core modules are always preferentially loaded if their identifier is
passed to require(). For instance, require('http') will always return
the built in HTTP module, even if there is a file by that name.
Here's the basic setup. I'm trying to create a simple middleware component that would allow me to easily pass data from my route directly to my javascript in the client side. (Very similiar to the Gon gem in ruby). The way I'm doing it is by having a module that looks like this:
module.exports = function(){
return function(req,res,next){
var app = req.app;
if(typeof(app) == 'undefined'){
var err = new Error("The JShare module requires express");
next(err);
return;
}
res.jshare = {};
app.dynamicHelpers({
includeJShare: function(req,res){
if(typeof(res.jshare) === 'undefined'){
return "";
}
return function(){
return '<script type="text/javascript">window.jshare=' + JSON.stringify(res.jshare) + '</script>';
}
}
});
next();
};
}
Then, in my route I can do this:
exports.index = function(req, res){
res.jshare.person = {firstName : "Alex"};
res.render('index', { title: 'Express' })
};
Finally in the layout.jade:
!{includeJShare()}
What that does is in outputs a line of javascript on the client that creates the exact JSON object that was created server side.
Here's the question; it all works as expected, but being new to Express and Node.js in general, I was just curious if attaching properties onto the response object is OK, or is there something wrong with doing it that I'm simply overlooking? For some reason it doesn't pass my "smell test" but I'm not sure why.....
I know this is an old thread, but there is something else to add to this topic.
Express has a response.locals object which is meant for this purpose - extending the response from middleware to make it available to views.
You could add a property directly to the response object, and as #hasanyasin indicated, is how JavaScript is designed. But Express, more specifically, has a particular way they prefer we do it.
This may be new in express 3.x, not sure. Perhaps it didn't exist when this question was asked.
For details, see
http://expressjs.com/en/api.html#res.locals
There is also an app.locals for objects which don't vary from request to request (or response to response I suppose).
http://expressjs.com/en/api.html#app.locals
See also: req.locals vs. res.locals vs. res.data vs. req.data vs. app.locals in Express middleware
It is perfectly OK. It is how JavaScript is designed. Only thing you should be careful is to not accidentally overriding already existing properties or being overridden by others. To be safer, instead of adding everything directly to req/res objects, you might consider going a level deeper:
res.mydata={}
res.mydata.person= ...
Like that.
Use res.locals for including custom variables in your response object.