I have 2 variables in env file. For Port and mongoDB link. I have tried many solutions on the internet but i am not able to access the values in the listen method nor in database connection.
Here is my sever file code:
const app = require("./app");
const connectDatabase = require("./config/database");
// Config
require("dotenv").config({ path: "backend/config/config.env" });
// Connecting to database
connectDatabase();
app.listen(process.env.PORT, () => {
console.log(`Server is working on http://localhost:${process.env.PORT}`);
}); // I can run the app if i use any port number in place of "process.env.PORT"
Note: I have put the wrong password here to hide my credentials.
I have tried to use env file in root directory also but it did not resolve the issue. The thing is i can access the values in the console but not in the listen method or in connection method.
I can run the app with direct values.
Here is the listen method error screenshot:
Right now you are passing 3000; to the listen function, you need to pass 3000.
Remove the semicolons ; from the env file and it should work.
Have a look at the dotenv npm page here for examples.
Also, you have posted your mongodb credentials online, I'd suggest you change those immediately.
Related
I have a working forge application ( bim360 hub sidebar with forge viewer and some charts).
It is currently running from Visual Studio Code IDE only. I want to build the app into an .exe file in order to be able to send it to a user, upload it to a server with IIS, etc..
General details:
I used Petr Broz tutorial to set up the backend of the viewer and hub
(Forge online training - view your models https://www.youtube.com/watch?v=-O1e3gXCOEQ&t=8986s )
The app is running on Node.js
I tried to use 'nexe' module and build executable file. With this method, I need to specify index.js file ("an entry point") and define a 'nexe.config.js' file. I used the entry point start.js.
Eventually, I managed to create an exe file - and when I run it from the command line, I get an error
Missing FORGE_CLIENT_ID or FORGE_CLIENT_SECRET env. variables.
although I have them in the config.js
Main questions:
Is there another way to build a close exe file from visual studio code - for a forge web application?
Am i doing something wrong with the processes I mention above?
Is it even possible to deploy a web application to IIS using an exe file?? all of the documentation points toward Azur, AWS and heroku..
Relevant files:
1) start.js:
const path = require('path');//bringing in built in node js modeules ( to resulve file system path )
const express = require('express');//module to create the express server
const cookieSession = require('cookie-session');
//any piece of code would have an opportunity to handle the request
const PORT = process.env.PORT || 3000;
const config = require('./config.js');
if (config.credentials.client_id == null || config.credentials.client_secret == null) {
console.error('Missing FORGE_CLIENT_ID or FORGE_CLIENT_SECRET env. variables.');
return;
}
let app = express();
//static middlewere to check for the front end files (html,js,css)
app.use(express.static(path.join(__dirname, 'public')));//method inside express module: a middlewere for serving static files this line will check in 'public' folder if the request
//that is sent (specific file) is in there. if so - it will ignore the rest of the stack(the rest of the code)
app.use(cookieSession({
// create 2 cookies that stores the name and encripted key
name: 'forge_session',
keys: ['forge_secure_key'],//takes cater of decipher the encription for the forge key for us
maxAge: 14 * 24 * 60 * 60 * 1000 // 14 days, same as refresh token
}));
app.use(express.json({ limit: '50mb' }));//middlewere that looks at the title of the request - and if its .json it will look at the body of the request and parese it to javascript object
app.use('/api/forge', require('./routes/oauth.js'));//adding our custom express routers that will handle the different endpoints.
app.use('/api/forge', require('./routes/datamanagement.js'));
app.use('/api/forge', require('./routes/user.js'));
app.use((err, req, res, next) => {
console.error(err);
res.status(err.statusCode).json(err);
});
app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); });
2) config.js:
// Autodesk Forge configuration
module.exports = {
// Set environment variables or hard-code here
credentials: {
client_id: process.env.FORGE_CLIENT_ID,
client_secret: process.env.FORGE_CLIENT_SECRET,
callback_url: process.env.FORGE_CALLBACK_URL
},
scopes: {
// Required scopes for the server-side application-->privliges for our internal opperation in the server side ("back end")
internal: ['bucket:create', 'bucket:read', 'data:read', 'data:create', 'data:write'],
// Required scope for the client-side viewer-->priveliges for the client ("front end")
public: ['viewables:read']
}
};
Author of the tutorial here :)
I'm not sure how nexe works exactly but please note that the sample app expects input parameters such as FORGE_CLIENT_ID or FORGE_CLIENT_SECRET to be provided as environment variables.
As a first step, try running your *.exe file after setting the env. variables in your command prompt.
If that doesn't work, try hard-coding the input parameters directly into the config.js file (replacing any of the process.env.* references), and then bundle everything into an *.exe file. This is just for debugging purposes, though! You shouldn't share your credentials with anyone, not even inside an *.exe file. So as an alternative I'd suggest that you update the sample app to read the input parameters from somewhere else, perhaps from a local file.
after trying a lot of solutions, i got to the conclusion that the reason that nothing happened was that the oathantication files ( with the clint_id and clint_password) was not embedded in the .exe file.
the way to include those files with the nexe module is to use the flag -r "Foldername/subfoldername/filename.js".
first, crate a nexe.config.js file that would contain the entry point file name to the app. ( in my case, the file name is " start.js")
second, write the following commands in the command line:
cd C:\Projects\MyAppFolder
npm install -g nexe
// specify all the files you want to include inside the exe file
nexe start.js -r "config.js" -r "nexe.config.js" -r "routes/common/oauth.js" -r "routes/*.js" -r "public//." -r ".vscode/**/." -r "package-lock.json" -r "package.json" --build --output "AppName.exe"
I'm new to coding. I have a node.js application which I have deployed using "Heroku.com". I want to use a custom domain for the application as well as having SSL active using the custom domain. When the application uses the default domain given by Heroku, SSL is automatically in place, however if I want SSL to work when I use a custom domain, I have to include the following code in my app.js file in order for SSL to work:
app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https')
res.redirect(`https://${req.header('host')}${req.url}`)
else
next()
});
This works fine, however when I am maintaining my app locally (in VS Code) and use localhost:3000 for testing purposes I have to comment out the code above in order to be able to view the app using locahost because of something to do with localhost not working with HTTPS.
So my question is, is there a code (if statement or something of the like) that will run that code if its being used in a live environment or to not run if its being used in localhost. This is mainly so I don't have to continue to comment out the code before and after deployment and testing.
If you have any other advice or better solutions for this kind of thing I would appreciate it.
Cheers,
Sam
You can use the concept of environment variables to differentiate between the production enviroment (live website on heroku) and the development environment (localhost). Specifically, you can set an environment variable NODE_ENV (just a popular naming convention, nothing in-built) to a value that can be used inside your code logic to perform actions based on the environment.
You can access the value by writing
const env = process.env.NODE_ENV;
Note: You have to set the environment variable first, otherwise process.env.NODE_ENV is just going to be undefined.
How to set the environment variables?
There are a couple of ways, like having a .env file, passing through CLI, etc. I'll show you a quick way. While running your server on localhost, write this,
NODE_ENV=development node server.js
Now, inside your server.js, you can do something like
// If NODE_ENV is undefined, assume production
const env = process.env.NODE_ENV || 'production';
app.use((req, res, next) => {
if (env === 'production' && req.header('x-forwarded-proto') !== 'https') {
res.redirect(`https://${req.header('host')}${req.url}`)
}
else {
next()
}
})
You can have as many environments as you like (development, testing, production, staging, etc.) Also check out dotenv module
[Edit]
Create folder called config inside add settings.js
package.json
app.js
--config // Will hold your configuration settings
----settings.js // Your settings
In settings.js
const settings = {
development: {
// Developpment configuration settings
email: 'development#gmail.com'
},
staging: {
// staging settings
email: 'staging#gmail.com'
},
production: {
// Production configuration settings
email: 'production#gmail.com'
},
}
const getSettings = () => {
if (!process.env.NODE_ENV) return settings.development
if (process.env.NODE_ENV === 'staging') return settings.staging
return settings.production
}
module.exports = getSettings()
what is proccess.env.NODE_ENV? It's an enviroment variable which if you didn't declare will return undefined and you can make it's variable different by setting it from the terminal
When you go to development try to run this command in the hoster terminal
export NODE_ENV=production
DON'T RUN THIS IN YOUR LOCAL TERMINAL, try to ask your web hosters how to run a command in their command line to store environment variable
for heroku: heroku run export process.env.NODE_ENV
DON'T WRITE ANY SENSITIVE DATA THERE! store them in environment variables too
Also for the port you would want to do something like this in your app.js
const port = process.env.PORT || 3000
Assume that I have two files.
server.js
test.js
server.js have all the initialization codes in place (Mongoose, Express..etc). It also has the below code:
const io = require('socket.io')(server);
In my test.js file, I have something related to mqtt. It is irrelevant, however, please understand that I don't have any variable access in there (req, app). Because that file isn't part of the route or anything.
It is included in server.js as:
require('test.js');
I am not getting into any details of MQTT or how it works. Consider that one or more functions inside test.js is running on a specific time. So, when ever that happens, how can I emit an event using socket.io from the test.js file?
My client side dashboard is ready to receive the event. I am just confused how to design the system, especially how to access the io variable which exist in server.js file.
As mentioned already just export a function from test.js that takes io as a parameter:
module.exports = function test(io) {
io.on("connection", socket => {
socket.emit("greeting", "hello world!");
});
};
From your server.js you just have to pass in the argument:
require("./test.js")(io);
I'm following Heroku's tutorial to create a contact list using the MEAN stack (Heroku's running example here). I'm able to deploy it to Heroku and it works there. But when I run it locally on my machine, the browser (Chrome 67.0.3396.87 on macOS High Sierra) only displays a "Cannot GET /" message.
I believe it's related to how the Angular build directory /dist/ referenced in line 12 of server.js does not exist (as far as I can tell). The beginning of server.js looks like this:
var express = require("express");
var bodyParser = require("body-parser");
var mongodb = require("mongodb");
var ObjectID = mongodb.ObjectID;
var CONTACTS_COLLECTION = "contacts";
var app = express();
app.use(bodyParser.json());
// Create link to Angular build directory
var distDir = __dirname + "/dist/";
app.use(express.static(distDir));
// Create a database variable outside of the database connection callback to reuse the connection pool in your app.
var db;
I looked into it and found that Angular deletes the /dist/ directory upon ng serve. I also found that there is a flag --delete-output-path whose default is true.
I set the --delete-output-path flag to false in .angular-cli.json as recommended by this answer as well as in /node_modules/#angular/cli/lib/config/schema.json. Despite those changes (trying to set the flag in one file, or the other file, or both files at the same time), I'm still getting the "Cannot GET /" message and the /dist/ directory still doesn't appear to be there.
The only way I've been able to even run part of the app is to change server.js's line 12 reference from /dist/ to /src/. This allows /src/index.html to begin loading at localhost:5000/ (the browser displays the text "Loading..." as specified in line 16 of index.html) and gets the contacts API up and running at localhost:5000/api/contacts/. But the Angular components (the list of contacts that is the purpose of the tutorial) don't load. Maybe because I changed the build directory to a totally different location.
Is there something with the /dist/ directory that I'm missing? Or does my issue with getting the app to run locally have nothing to do with /dist/ at all?
Notice that you don't have a way of handling requests to the route '/' since the line:
app.use(express.static(distDir));
only ensures that all bundled files generated in your "dist" folder are accessible when your index.html requires them, but you still have to serve the index.html itself. When using the MEAN stack one normally would do something like this:
app.use ('/api', yourApiRouter);
//and for everything else let the client-side routing handle the route:
app.get ('*', function(req, res) {
res.sendFile(distDir + 'index.html');
}
I recommend to use the native "path" module to join your __dirname with your "dist" folder and your index.html location rather than simple concatenation.
You can use an arrow function instead of a callback when using app.get function if you are using ES6
I'm using supertest to unit test my server configurations and route handlers. The server configurations tests are in test.server.js and the route handling tests are in test.routes.handlers.js.
When I run all the test files using mocha ., I get EADDRINUSE. When I run each file individually, everything works as expected.
Both files define and require supertest, request = require('supertest'), and the express server file, app = require('../server.js'). In server.js, the server is started like so:
http.createServer(app).listen(app.get('port'), config.hostName, function () {
console.log('Express server listening on port ' + app.get('port'));
});
Is there something wrong in my implementation? How can I avoid EADDRINUSE error when running my tests?
mocha has a root Suite:
You may also pick any file and add "root" level hooks, for example add beforeEach() outside of describe()s then the callback will run before any test-case regardless of the file its in. This is because Mocha has a root Suite with no name.
We use that to start an Express server once (and we use an environment variable so that it runs on a different port than our development server):
before(function () {
process.env.NODE_ENV = 'test';
require('../../app.js');
});
(We don't need a done() here because require is synchronous.) This was, the server is started exactly once, no matter how many different test files include this root-level before function.
Try requiring supertest from within a root level before function in each of your files.
Answering my own question:
My supertest initialization looks like this:
var app = require('../server.js');
var request = require('supertest')(app);
In test.server.js, I had these require statements directly inside a describe. In test.routes.handlers.js, the statements were inside a before inside a describe.
After reading dankohn's answer, I was inspired to simply move the statements to the very top outside any describe or before and the tests all run without problems now.