I was going through an article on web when I stumbled upon the following code snippet.
I this author have used babel to use ES6 syntax in node and have configured our app in two parts
App.js
Server.js
Inside our Server.js he have done something like this
import express from 'express';
import cors from 'cors';
const app = express();
function setPort(port = 5000) {
app.set('port', parseInt(port, 10));
}
function listen() {
const port = app.get('port') || 5000;
app.listen(port, () => {
console.log(`The server is running and listening at http://localhost:${port}`);
});
}
app.use(cors({
origin: '*', // Be sure to switch to your production domain
optionsSuccessStatus: 200
}));
// Endpoint to check if the API is running
app.get('/api/status', (req, res) => {
res.send({ status: 'ok' });
});
export default {
getApp: () => app,
setPort,
listen
};
Here this statement doesn't make sense to me
export default {
getApp: () => app,
setPort,
listen
};
And then in app.js, He have done this
import server from './server';
server.listen();
export default server;
Question: Can someone please explain me in stretch what is happening here? Like why is our getApp: () => app written like this and why setPort and listen written normally?
Ps: I know what does export default mean
The author is exporting an object with three properties as the default export.
Property 1: getApp -
This property has a value which is a function that returns the app variable from the server.js file, which is just the express instance. In other words, it is a method which returns the express app.
Property 2: setPort -
This property has a value equal to the setPort function defined in the server.js file
Property 3: listen -
This property has a value equal to the listen function defined in the server.js file
So when the author calls server.listen() in the app.js file, he/she is just calling the listen function which he/she has imported from the server.js file. Not exactly sure why they've chosen to set the app this way...
Well, put simply it's an inline function definition utilising ES6 arrow functions syntax which returns the internal app instance.
It's no different to:
getApp: function() {
return app;
}
The reason it's declared inline is because you don't actually have a function definition anywhere else in the module. If you added the function beforehand then it could be exported the same way as listen / setPort
Related
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
This question already has answers here:
Pass options to ES6 module imports
(9 answers)
Closed 2 years ago.
I've tried different ways to search for this and I am coming up with nothing. When setting up an express app and importing a file of routes you often see documentation for this statement:
require('./app/routes/posts.routes.js')(app)
Which from the documentation in nodejs.org means to require the file './app/routes/posts.routes.js' and run everything in the app object.
What I have not come across is how to write this statement using "import".
My example:
Route File Contents
module.exports = (app) => {
import posts from '../controllers/post.controller.js'
app.post('/posts', posts.create);
app.get('/posts', posts.findAll);
app.get('/posts/:postId', posts.findOne);
app.put('/posts/:postId', posts.update);
app.delete('/posts/:postId', notes.delete);
}
Import Statement
//this does not work throws Error: Cannot find package 'app' imported from /Users/matt1/socialbulk/server/server.js
import posts from 'app/routes/post.routes.js' //what do you do with (app)?
app.use('/posts', posts)
app.listen(3000, () => {
console.log("Server is listening on port 3000");
});
Thank you so much in advance for your help!!!!
module.exports = foo is equivalent to export default foo
Here foo is a function
import posts from 'app/routes/post.routes.js' //what do you do with (app)?
app.use('/posts', posts(app))
app.listen(3000, () => {
console.log("Server is listening on port 3000");
});
Forgive me if this is something you shouldn't do, but I've looked around to see what is possible.
I want to verify that my express app has a middleware called/used for the app.
import express from 'express';
import cors from 'cors';
const app = express();
app.use(cors()); // <----- I WANT TO TEST THIS
app.get('/', (_req, res) => res.send({ hello: 'world' });
app.listen(5000, () => console.log(`Listening on port 5000`));
export default app;
Potential jest test
import app from './index.ts';
// This is a poor attempt to try and get this to work
test('test if CORS is implemented', () => {
const mockCors = jest.mock('cors');
const myApp = app;
expect(mockCors).toHaveBeenCalledTimes(1);
});
If anyone has the solution and if I should not be doing this, what is the reason behind it?
My guess is that you don't actually care that cors is called. Your client won't say to you "I want the cors middleware to be called". All the client should care about is the service that is provided, not how it's implemented. Your tests should do the same. If you decide one day to use another module for CORS, your tests shouldn't need to change, why would they?
My (personal) preferred approach is exactly that. Testing that given some input, my programs gives me the output I desire. Everything inside the program can be changed, as long as the behavior does not change. That will give you peace of mind when refactoring.
Also, for testing an Express app, you don't need a server, you just need the app. Actually starting the server can add complexity to your tests, since they might be hanging if you forget to close the server after them.
So in this example, the very first thing I would do is move everything you have in index.ts into a file called app.ts, and remove this line:
app.listen(5000, () => console.log(`Listening on port 5000`));
And in index.ts, only have this:
import app from './app.ts';
// Start the server
app.listen(5000, () => console.log(`Listening on port 5000`));
Then, I would use Supertest along with Jest, to make requests to that app:
npm i -D supertest
And then, in your test file, test what matters to the client:
import request from 'supertest';
import app from './app.js'; // Just import the app, not the server
describe("myApp", () => {
it('should implement CORS', async() => {
const { headers } = await request(app).get('/');
expect(headers['access-control-allow-origin']).toEqual('*');
});
});
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.
I have an Express.js project where I am allowing plugins to be loaded and unloaded at runtime. Plugins have access to the Expess.js router stack to register their paths just like a normal script would such as:
var express = require('express');
var router = express.Router();
module.exports = function(projectCoreObject) {
function Plugin() { }
// Plugin initialize called when a plugin is loaded.
Plugin.Initialize = function (done) {
// Register the router..
projectCoreObject.app.use('/', router);
};
// GET - /test
router.get('/test', function(req, res, next) {
res.send('Success!');
});
return Plugin;
};
While this all works great, I have the issue with unloading plugins removing their router from the stack.
Is there a proper way to remove a full router object from Express.js' stack at runtime? I can do individual middleware using their names but with a route like this example shows, the name is just 'router' in the stack.
I resolved this by using a named function trick to take an anonymous function and turn it into a named one. This way I can remove the router by its name then.