exported object is undefined in nodejs - javascript

I am using multer in index.js and i need to use an object which has multer storage engine in other routes. So i have exported the object but the problem is when i i try to use it in the route file its undefined.
index.js
const storage = new GridFsStorage({//some config})
const upload = multer({storage})
app.use('/posts',postRouter)
//if i use the middleware upload.single('file') here, will it affect all the routes like(posts/a,posts/b)?
exports.upload = upload
postRouter.js
const index = require('../index')
setTimeout(() => {
console.log(index.upload)
}, 1000);
console.log(index.upload)
i tried using setTimeout and its giving me the expected result but outside settimmeout its undefined.
why is this happening. what is the best way to apply the multer middleware in some other routes by exporting it from index?
the problem is GridFs is taking sometime to connect and do its work, but before that this upload object is exported . thats why above scenario occurs. any idea how to avoid that?

As GridFsStorage is asynchronous, so it need some time to init. And you can just
pass upload as param to the postRouter function.
app.use('/posts', postRouter(upload))

Related

Use middleware only for json server specific routes

How can I use a middleware ONLY FOR my json-server specific routes? In the json-server docs, I can see the following instructions:
const jsonServerRouter = jsonServer.router('mock-server/db.json')
server.use(customMiddleware)
server.use(jsonServerRouter) // customMiddleware should be executed ONLY FOR this jsonServerRouter
/*
Problem is here, customMiddleware has already been executed,
so following routes will use the middleware too
*/
server.use(otherRoutes)
What I've tried:
// This syntax is similar to the previous code. So it doesnt work
server.use(customMiddleware, jsonServerRouter)
// Passing the middleware to the 'router' function doesnt work
const jsonServerRouter = jsonServer.router('mock-server/db.json', customMiddleware)

not able to acces db() from exported MongoClient module

I am not able to export the client properly from db.js to User.js
db.js
const some= MongoClient.connect(process.env.CONNECTIONSTRING).then((client) =>{
module.exports=client
const app = require("./app")
app.listen(process.env.PORT)
})
Using the client here , i can do methods like client.db().collection("users");
But i am not able to do using the user.js
User.js
const usersCollection = require("../db").db().collection("users");
This gives error saying const
usersCollection = require("../db").db().collection("users");
^
TypeError: require(...).db is not a function
I maybe wrong but in the callback function for MongoClient the first argument is the error and second argument is for client.(err,client)
so you are calling db() on error and not client
And also try to export from global scope as mentioned by Maxime in the comment
You have this problem because you are importing something that is asynchronous and when you do it in 1 line the client is not ready when you try to call it with db().collection("users").
You can verify if the async is the issue by changing your code to this:
const temp = require("../db")
setTimeout(() => {
temp.db().collection("users")
}, 1000)
You can also check here for an example how to do the connection to the DB properly https://www.terlici.com/2015/04/03/mongodb-node-express.html

Next Js Server Side Api Read and Write JSON

I'm trying to write a basic local api for myself using Next.js, it is a timeline generator, and I am stuck at actually reading the file from the api folder.
What do I want in my local aplication:
1.A simple page where I can input an event, with a date and description
2.Open a list.json file somewhere and push that new event to that json file, writing on it.
What I am currently doing and where I am stuck:
I am aware we cant write on files on the client side, so I started looking at the api routes in next js to access the JSON file, but I cannot even manage to read it!
I have an api folder inside pages folder, and in this api folder I have two files: one is the list.json file, where I previously manually write some events with respective dates; and the other is getlist.js, with this code:
var fs = require('fs');
export default function getList(req, res) {
const rawList = fs.readFile('list.json');
var list = JSON.parse(rawList);
res.json(list);
}
Now on the pages folder I have a index.js file where I try to access this getlist.js api using getStaticProps(), like this:
import getlist from './api/getlist'
export async function getStaticProps(){
var list = getlist();
return {
props: {
list
}
}
}
I have tried using other stuff, like the fecth function, to get to getlist.js, but nothing I do seems to work.
Can anyone help me?
And since I'm already in here, how would I manage to get the input from the form I already have in my client side page and write it to that list.json file in my api folder?
There are two ways how you can read json in next.js:
Import inside getStaticProps [https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation]
export async function getStaticProps(context){
const example = await import('./api/example.json');
return {props: {example: example.default}}
}
Import or read in handler function inside api folder [https://nextjs.org/docs/api-routes/introduction]:
const fs = require('fs');
export default async function handler (req, res) {
const example = await fs.readFile('./example.json');
return res.status(200).json({example});
}
In order to write *.json file you need to send request with value to the server api (handler from api folder that was mentioned before).
That's how the part to write json will look like:
const fs = require('fs');
export default async function handler(req, res) {
//...
if (req.method === 'POST'){
fs.writeFileSync('./example.json', JSON.stringify(req.body))
return res.status(200).json({});
}
//...
}

Running Code When a Module is Loaded and Exposing It as Middleware

I am still trying to fully understand how exporting and importing modules works in Nodejs.
I am using the following file to seed a mongodb database. This file runs exactly as it should and returns exactly the result I am expecting, when I execute it as a standalone file. My issue is I want to use this file in two different places in my app. So I am trying to make it an exportable/importable module. Here is what I have tried:
seed.js looks like this:
'use strict';
// library modules
const {ObjectID} = require('mongodb');
const seeder = require('mongoose-seed');
const jwt = require('jsonwebtoken');
const util = require('util');
// local modules
const {Course} = require('./../models/course');
const {Review} = require('./../models/review');
const {User} = require('./../models/user');
const {data} = require('./../data/data.js');
const config = require('./../config/config.js');
/*==================================================
build seeding Courses, Reviews, Users
==================================================*/
// Connect to MongoDB via Mongoose
let seed = seeder.connect(process.env.MONGODB_URI, (e) => {
console.log(`Connected to: ${process.env.MONGODB_URI} and seeding files`);
// Load Mongoose models
seeder.loadModels([
'src/models/user.js',
'src/models/review.js',
'src/models/course.js'
]);
// Clear specified collections
seeder.clearModels(['User', 'Review', 'Course'], function() {
// Callback to populate DB once collections have been cleared
seeder.populateModels(data, function() {
seeder.disconnect();
});
});
});
module.exports = seed;
Within app.js I have these two lines
const seed = require('./middleware/seed');
and
app.use(seed);
I have also tried, to no avail
app.use(seed());
What is missing? I don't want to use the code in-line in two different places (DRY you know).
It is failing with this error:
throw new TypeError('app.use() requires a middleware function')
I am sorry about the formatting I thought I was using markdown, but I am clearly not.
You are executing your seeder function in that module and not returning any middleware function at all. Middleware is always a function and it has the form of:
const seed = function (req, res, next) {
...
next()
}
With what you have now, the best you can do is the following which will certainly seed your models when the module is loaded.
const seed = require('./middleware/seed');
Are you trying to run those two functions as middleware, on every request? In that case you'd do something like this:
const seed = function (req, res, next) {
seeder.connect(..., (e) => {
...
seeder.clearModels(..., ()=>{
...
next()
})
})
})
If you want to run that seeder code at the module level AND to expose it as middleware then wrap the current module level code in function and execute it when the module loads. Notice that the new function optionally handles the next callback if it receives it.
function doSeed(next){
//your code currently running at module level
if(next)
return next()
}
doSeed(); //run the code at the module level
const seed = (req, res, next) => doSeed(next))
module.exports = seed;
One way that I allow myself to have access to a variable in different instances is adding it to the process variable. In node.js no matter where in the project it is, it will always be the same. In some cases, I would do process.DB = seed(); which would allow process.DB to always be the result of that. So inside your main class you can do process.DB = seed(); and all of your other classes running off of that one main class would have access to process.DB keeping your database readily available.

node.js variable scope with routes separation

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.

Categories