module.exports = ({}) vs {} - node.js

I work with Koa middleware and in some code I use this code in router:
module.exports = ({router}) => {
//some code
}
if I do:
module.exports = {router} => {
//some code
}
the nodejs app throws an error. So whats the difference between these two different exports except the error part?

{(router)} is just wrong. You should see module.exports as a function so it has () where the arguments go, which in this case is an object {} of the functions you want to export (here router, but it could be multiple just as well.
I think this article gives a very clear explanation: https://www.sitepoint.com/understanding-module-exports-exports-node-js/

Related

I can't understand how do 'global`s work in TypeScript/NodeJS and what is their difference?

I am reading a code like below:
import { MongoMemoryServer } from "mongodb-memory-server";
import mongoose from "mongoose";
import request from "supertest";
import { app } from "../app";
declare global {
function signin(): Promise<string[]>;
}
let mongo: any;
beforeAll(async () => {
process.env.JWT_KEY = "asdfasdf";
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
const mongo = await MongoMemoryServer.create();
const mongoUri = mongo.getUri();
await mongoose.connect(mongoUri, {});
});
beforeEach(async () => {
const collections = await mongoose.connection.db.collections();
for (let collection of collections) {
await collection.deleteMany({});
}
});
afterAll(async () => {
if (mongo) {
await mongo.stop();
}
await mongoose.connection.close();
});
global.signin = async () => {
const email = "test#test.com";
const password = "password";
const response = await request(app)
.post("/api/users/signup")
.send({
email,
password,
})
.expect(201);
const cookie = response.get("Set-Cookie");
return cookie;
};
I can't understand the purpose of global.signin function and how does it work? I guess it has something to do with Jest but as long as I know the Jest codes should be inside the __test__ folder with the same file name and .test.ts extension. But the above function is defined and used inside the setup.ts file in the root of the application.
I also see some codes like following:
declare global {
namespace Express {
interface Request {
currentUser?: UserPayload;
}
}
}
In some .ts files of the project as well that I am not sure are these global variables the same as the other globals I mentioned above or these are different things? I am interested to know how this global variables work as well?
The piece of code you shared is making use of global augmentation https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation
// Hint typescript that your global object will have a custom signin function
declare global {
function signin(): Promise<string[]>;
}
// Assign value to global.signin
global.signin = async () => { /* implementation */ };
Likely one or multiple modules ("mongoose", "supertest", "../app") imported by the test file is using global.signin (or window.signin) at some point (or maybe one of their nested imports is => look for "signin(" in the project). Thus for testing purposes, global.signin needed to be mocked. However just adding global.signin = something would raise a typescript error, because signin is not a standard global variable. This is where declare global comes into play. It hints typescript that in your particular context, a signin function is expected to exist in global scope.
JavaScript/TypeScript running in node will try to resolve anything it can't find in the current local scope in global (the same way a browser would look in window). Any function or variable you can access globally (e.g. setTimeout()), can also be accessed with global. as prefix. It just makes it explicit.
What happens in your code are two things:
declare global {
function signin(): Promise<string[]>;
}
Here it tells typescript's type system that the global object also has a function called signin. This part is not required but it makes sense required for typescript to allow you to access / define that function, in JavaScript you simply define it.
https://www.typescriptlang.org/docs/handbook/declaration-merging.html has some details how declare works.
global.signin = async () => {
// code ...
};
And here it is actually added to the global object.
In JavaScript non strict mode you could even write (notice the lack of var/let/const/global.)
signin = async () => {
// code ...
};
I don't see signin getting used anywhere in that code so the reason for it is unclear to me. As long as the file that defines it gets loaded you can call the function simply by referring to it as signin(). The global. is added implicitly.
The purpose of
declare global {
namespace Express {
interface Request {
currentUser?: UserPayload;
}
}
}
is more practical, in express you may want to add properties to your requests that get added by middleware. By declaring that the Express Request has a property called currentUser you get to do
app.get((req, res) => {
const user: UserPayload = req.currentUser
...
})
without typescript complaining about an unknown property.
More on that for example https://blog.logrocket.com/extend-express-request-object-typescript/

Include models in other script

I want to have a global script that I can include system wide for some helper files.
This is the helper file (helper.js):
async function hasStock() {
}
// Export it to make it available outside
module.exports.hasStock = hasStock;
But now the problem, I have a model that I give in the index.js, the model is only available there:
app.use('/api/parts', require('./routes/part.js')(app, models));
But I also need that model (models) at my helper.js file.
So I thought I need to do this in part.js (from /api/parts):
module.exports = function (app, models) {
require("../helpers/helper.js")(models);
}
But that isn't also good I think. What is a good solution to include the models (models object only available in the index.js) and to use this system wide in helpers.js?
You should try to export the function hasStock by following method ,
In your helper.js file
const anyObjectName = {
hasStock : async function hasStock {
}
}
//like this export , you can use this object and it's function anywhere .
module.exports = anyObjectName;
In your part.js (from /api/parts):
var anyObjectName = require('../helpers/helper.js');
//now you can access the hasStock function in part.js file like
anyObjectName.hasStock();
Hope it is useful for your and solves your problem .

What is exports.install in node js?

Hi I found a framework where they use a lot this pattern.
exports.install = function(){
//code
}
but usually you see this pattern in nodejs
module.exports = {
//code
}
Is this the same thing or is this something else ?
exports is the object corresponding to module.exports before you do anything to it. I think it's due to some legacy code, but basically folks use module.exports if they want to replace the whole object with their own object or a function, while they use exports if they just want to hang functions off the module. It's a little confusing at first, but essentially exports.install just means that calling code would do something like:
const mod = require('that-module');
mod.install(params, callback); // call that function
The framework you're looking at is probably using it as part of a bootstrapping process, afaik it doesn't have significance to the node engine itself.
Yes, it is the same thing. You can use one of 2 ways to setup your code.
The different thing is memory. They point to same memory. You can think exports like a variable and you can not use this way to export your module:
Given this module:
// test.js
exports = {
// you can not use this way to export module.
// because at this time, `exports` points to another memory region
// and it did not lie on same memory with `module.exports`
sayHello: function() {
console.log("Hello !");
}
}
The following code will get the error: TypeError: test.sayHello is not a function
// app.js
var test = require("./test");
test.sayHello();
// You will get TypeError: test.sayHello is not a function
The correct way you must use module.exports to export your module:
// test.js
module.exports = {
// you can not use this way to export module.
sayHello: function() {
console.log("Hello !");
}
}
// app.js
var test = require("./test");
test.sayHello();
// Console prints: Hello !
So, it just is style of developer.

Undefined class with ES6 and Sails.js

I am developing a sails.js app. I am using using node v4.2.1. I am trying to write a class which should be called within my api.
In my controller, I have written
'use strict';
class Sample {
disp() {
return "hello world";
}
}
module.exports.Sample = Sample;
In my api, I am trying to use
//Included the class file above the controller.
//var Sample = require('../repositories/ExampleRespository.js');
test: function (req, res) {
var sample = new Sample();
}
Sample seems to be undefined.
I have tried module.exports = Sample; I am still facing the same error.
Am I doing something wrong?
Apologies if the question is silly.
You're exporting Sample as the default, so your import should look like this:
var Sample = require('../repositories/example.js');
test: function (req, res) {
var sample = new Sample();
...
}
Either that, or export it as Sample:
module.exports.Sample = Sample;
EDIT: so, to be clear:
One solution:
// example.js
...
module.exports = Sample;
// API file
var Sample = require('../repositories/example');
Another solution:
// example.js
...
module.exports.Sample = Sample;
// API file
var Sample = require('../repositories/example').Sample;
Your export statement should be:
module.exports = Sample;
Then you will be able to:
var Sample = require('../repositories/example');
Note: you do not need .js on the end of a require statement.

How to get list of all routes I am using in restify server

I have a app designed as follows;
//server.js =====================================================
var restify = require('restify'),
route1 = require('./routes/route1),
route2 = require('./routes/route2),
....
....
....
var server = restify.createServer({
name: 'xyz_server'
});
route1(server);
route2(server);
Now each route file looks like belwo
//route1.js =====================================================
module.exports = function(server) {
server.get('/someRoute',function(req,res,next){
//.. do something
});
server.get('/anotherRoute',function(req,res,next){
//..something else
});
};
Now the issue is tht we have dozen's of route files and hundreds of routes in total.
There are multiple developers working on this project and several routes are being added daily.
Is there a function in restify gives me a list of all routes in the system ?
What i am looking for is something like:
server.listAllRoutes();
Is anyone aware of this ?
Try something like this
function listAllRoutes(server){
console.log('GET paths:');
server.router.routes.GET.forEach(
function(value){console.log(value.spec.path);}
);
console.log('PUT paths:');
server.router.routes.PUT.forEach(
function(value){console.log(value.spec.path);}
);
}
listAllRoutes(server);
This should list all GET and PUT paths, adding POST and DELETE should be easy :)
2019 update: server.router.routes is no longer available instead we have server.router.getRoutes() which returns a Map. So we can log all the routes using:
function listAllRoutes(server) {
Object.values(server.router.getRoutes()).forEach(value =>
console.log(
`ENDPOINT REGISTERED :: ${value.method} :: ${server.url}${value.path}`
)
);
}
http://restify.com/docs/server-api/#server
There is a router.getRoutes() method, but it returns an object which is not the best to work with for listing things. You could fiddle around with that to turn it into an array with the shape that you like.
Alternatively, you can access all the routes as an array and then map them, even better if you use a lib like better-console to give you console.table in node. The following is working nicely for me in restify#8.3.0:
import console from 'better-console';
function listRoutes(server) {
const { routes } = server.router._registry._findMyWay; // beware these are probably meant to be private APIs, they could be subject to change
const mapped = routes.map(({ method, path }) => ({ method, path }));
console.table(mapped.sort((a, b) => a.method > b.method));
}

Resources