heroku node.js tutorial - send env variables to other js pages - javascript

so i'm in the process of doing the 'getting started' on the heroku page.
by cloning their tutorial repo, i have decided to add my own index.html and app.js files into the /public folder they already created for me.
directory looks like this:
node-getting-started repo folder
| node_modules folder
| public folder
| | app.js
| | index.html
| index.js
| package.json
| Procfile
the package.json's main points to index.js which looks like this:
index.js
var express = require('express');
var app = express();
app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));
app.get('/', function(request, response) {
var obj = { ... };
var secret_key = process.env.SECRET_KEY;
// what should i do here to send the variables above to my app.js file?
// response.send(secret_key) ???
});
app.listen(app.get('port'), function() {
console.log('Node app is running on port', app.get('port'));
});
at this point, what i'm trying to do is send that obj within the index.js to my app.js file so i can use it there.
is this is the right way to go about this? is there some other (proper?) way of sending it to the other file?
i would basically want to do the same thing with environment variables such as setting a var secret_key = process.env.SECRET_KEY in the index.js and sending it to the app.js so that i could use it there, too.
Could someone explain to me how I could go about doing this?

In order to pass varying data from the server to the page being viewed you need to render it. This is different from serving a static file.
Express supports different template engines such as Jade, EJS and Handlebars. Here's a quick example using little help from express-generator. First create example project by running
$ mkdir example
$ cd example
$ sudo npm install -g express-generator
$ express -e
Then in routes/index.js you can find the relevant part that renders view called index and passes a title along.
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
The next part of your problem is to figure out howto pass data from your html to the app.js loaded in <script> element.

Assuming you would like to keep the SECRET_KEY hidden from users, you can't send it to the client. In that case, you'll want to move the functionality that requires the key to the server.
For an API request that requires a key, have the client request to your server and the server will make the request to the API with the key. You'll want to modify the app.get route:
// '/api-request' will be the URI that the client uses
// the callback will handle what the server does when it receives a request with this URI
app.get('/api-request', function(req, res){
request('API_URL' + process.env.SECRET_KEY, function(err, data) {
// send error to the client -- res.send exits the function and ends the request
if (err) res.send(err)
// send data to the client
res.send(data)
})
})
Your server will act as a middleman to the API, keeping your key unexposed and contained to the server.
On the client, the request will receive whatever data the server sends back with res.send. Client has no idea there was a middleman involved.
// the browser is smart and knows that a leading / refers to the current domain
request('/api-request', function(err, data) {
if (err) // handle error
// do stuff with the data
console.log(data)
})
Other operations that require a key can be handled in a similar manner. Your server will need a route to which the client will send a request with any relevant info and the server will send any resulting data.

Related

Using dotenv for API keys in multiple JS files

I am new to web programming but not programming in general. I use node.js to create a website and am using dotenv to hide API info form github and am having some trouble understanding something.
My .env file is in the root directory and contains:
GOOGLE_CALENDAR_API_KEY=key_value
I use an app.js file to set up and run my server and send the index.html file.
//jshint esversion:6
const https = require('https');
const bodyParser = require("body-parser");
const express = require("express");
require("dotenv").config();
const app = express();
app.use(express.static("public"));
app.get("/", function(req, res) {
res.sendFile(__dirname + "/index.html");
});
app.listen(5000, function(req, res) {
console.log("Listening on port 5000.");
});
Then I have another script file I use named "custom.js" to run the bulk of my webapp. Inside, I try to use process.env to get the API key.
window.onload = function()
{
const googleAPIkey = process.env.GOOGLE_CALEDAR_API_KEY;
.
.
.
but I get an error "Uncaught ReferenceError: process is not defined"
I have also tried moving the require("dotenv").config() line to the custom.js file and that fails. There is something I am doing wrong with trying to access information from one file into another, but I don't understand what.
Any help would be appreciated!
From what's i understood you trying to access the process variable of node.js app from the client browser and it is not possible. The process variable is only accessible in the scope of the node.js application and not in the browser where you run your client.
you have to add require("dotenv").config(); on second script file also
It looks like you are trying to access the Process variable on the client-side / frontend. You cannot access those variables from a client browser or machine

Modifying HTML Website from Node.js Server to Display File Data

So. I'm a total noob. And most of my question is geared towards just not understanding data transfer or Web servers properly.
Anyway, I am creating a project which hosts a very simple and lightweight Node.js server. In this server, I need to create a website to be able to view file data which resides on the server. On the server, I have a directory listing that goes something like this...
- info
--- client_IPAddress1
------ dataFile1.info
------ dataFile2.info
------ dataFile3.info
--client_IPAddress2
------ dataFile1.info
------ dataFile2.info
------ dataFile3.info
--client_IPAddress3
------ dataFile1.info
------ dataFile2.info
------ dataFile3.info
On the node server, I need to be able to read this file data, and modifying a table element on an html page to display the contents of the files. So far, all I know how to do is display the html page directly like this...
if(request.method == 'GET' && request.url == '/'){
response.writeHead(200, {"Context-Type": "text/html"});
fs.createReadStream("clientMonitor.html").pipe(response);
Now, I have a button like so...
<div class="refresh-btn" href="http://169.254.0.4:8888/client-data">
<p><b>Refresh</b></p>
</div>
Which I want to be able to refresh that data to display to a table element. So, on the node.js server what do I do here?
}else if(request.method == 'GET' && request.url == "/client-data"){
//TODO
}
I am a complete and total stranger to node.js. A quick solution or a link to a helpful website, or simple a link to a tutorial about data handling that covers topics akin to these would be extremely helpful. I am running this on a Raspberry Pi using Rasbian Jessie. If anyone knows another solution that they could point me for this platform, again, it would help.
Not sure what the output needs to be following your example, but I would surly start by using express.js in your project. This will simplify greatly your RESTfull api.
Depending on how noob, you are to node, I will try to guide you thru the simplest way I can! ;)
You first need to install Express in your node project.
From the command shell you type npm install express --save to install the node_module. The --save adds the dependency to your package.json. (Depending on your user's role, you might have to use the sudo command (sudo npm install express --save)
Using the following link Express "Hello World" example you will find the simplest example on how to use Express.
So if we use your example your setting might look like this.
var express = require('express')
var app = express()
app.get('/', function(req, res){
res.sendFile(__dirname + '/clientMonitor.html');
});
app.get('/client-data', function(req, res){
/* Depending on what you use on your client side,
you may get data here than send a response in json or flat data.*/
res.json(aJsonObject); // For json response {"Context-Type": "application/json"}
// OR
res.send('AnyValue'); // Will send 200, {"Context-Type": "text/html"}
// OR
res.sendFile(__dirname + '/someFile.html');
});
app.listen(8080, function () {
console.log('Example app listening on port 8080!')
})
For your client side, you may use any plugin such as DataTables.net or custom-made function that updates your data in your table using Ajax calls to refresh the information.
Hope this will help solve your issue!
If you decide to use POST instead of get, you will do something like :
app.post('/client-data', function(req, res){
var data = req.body.data;
}
Or if you wish to use queryStrings in the Get url parameters, you will do soemthing like :
app.get('/client-data/:id', function(req, res){
var data = req.params.id;
}

Node is not finding js files included in html

I'm trying to build a simple chat app using node and socket.io. I am following the tutorial listed here: http://socket.io/get-started/chat/
My issues is that the tutorial has some javascript that is placed in a script tag directly in the html. I would like to move this code into it's own js file.
I made a file called chat.js, that is in the same directory as my index.html and index.js. In my html I put the following code in the header (I also tried right before the ending body tag too)
<script type="text/javascript" src="chat.js"></script>
However, when I run node index.js in terminal and go to localhost, I get a 400 for chat.js. I've tried placing "/chat.js" as well as "./chat.js" with no luck. All three files are in the same directory.
Any clues to what I am doing wrong will be appreciated.
My index.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
node.js does not automatically serve any files like other web servers do. If you want it to send chat.js when the browser requests it, you will have to create a route for it in your node.js code so that the web server will send it.
If you use something like the Express framework, this can be done in perhaps one line of code with app.use(express.static(...)).
Notice how in the demo you linked to, there's a specific route for the / path. You need a similar route for /chat.js or you could use app.use(express.static(...)) to configure the automatic serving of a whole directory of files.
In the future, if you show your actual server code, then we could help more specifically with actual code that fits into your server.
Now that you've shown your code, you could add a specific route for /chat.js:
app.get('/chat.js', function(req, res){
res.sendFile(__dirname + '/chat.js');
});
Or, if you move chat.js to be in a public sub-directory under your app code, then you could serve all files in that directory automatically with this:
app.use(express.static('public'));
When Express gets a request for a route that doesn't have a specific handler, it will check the public sub-directory to see if a file matches the request name. If so, it will automatically serve that file.

How to do I get at my frontend on Heroku? The backend is up & running

I finally got my node/express & mongodb running on Heroku...but how do I get at my frontend?
I am most familiar with a localHost setup, where I simply open my index.html, running localHost servers with MAMP..
When I load myapp.herokuapp.com, I see a JSON of my MongoDB docs (currently empty)
{
"docs": []
}
And when I go to myapp.heroku.com/index.html I get my 404 error..
Where.. 404
This all makes sense, according to my express code:
app.get('/', function (req, res) {
getAll(res);
});
app.get('*', function (req, res) {
res.send("Where.. 404", 404);
});
How do I get to my index.html frontend? Is there any more code that would be helpful to see..
what app.use() calls do you have?
In particular, if you want to serve static .html files you need to add something along these lines (assuming your static file are located in the ./public sub-dir):
app.use(express.static(__dirname + '/public'));
Further details: http://expressjs.com/api.html#app.use

node.js /socket.io/socket.io.js not found

i keep on getting the error
/socket.io/socket.io.js 404 (Not Found)
Uncaught ReferenceError: io is not defined
my code is
var express = require('express'), http = require('http');
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
server.listen(3000);
and
<script src="/socket.io/socket.io.js"></script>
what is the problem ???
any help is welcome!
Copying socket.io.js to a public folder (something as resources/js/socket.io.js) is not the proper way to do it.
If Socket.io server listens properly to your HTTP server, it will automatically serve the client file to via http://localhost:<port>/socket.io/socket.io.js, you don't need to find it or copy in a publicly accessible folder as resources/js/socket.io.js & serve it manually.
Code sample Express 3.x -
Express 3 requires that you instantiate a http.Server to attach socket.io to first
var express = require('express')
, http = require('http');
//make sure you keep this order
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
//...
server.listen(8000);
Happy Coding :)
How to find socket.io.js for client side
install socket.io
npm install socket.io
find socket.io client
find ./ | grep client | grep socket.io.js
result:
./node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js
copy socket.io.js to your resources:
cp ./node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js /home/proyects/example/resources/js/
in your html:
<script type="text/javascript" src="resources/js/socket.io.js"></script>
It seems that this question may have never been answered (although it may be too late for the OP, I'll answer it for anyone who comes across it in the future and needs to solve the problem).
Instead of doing npm install socket.io you have to do npm install socket.io --save so the socket.io module gets installed in your web development folder (run this command at the base location/where your index.html or index.php is). This installs socket.io to the area in which the command is run, not globally, and, in addition, it automatically corrects/updates your package.json file so node.js knows that it is there.
Then change your source path from '/socket.io/socket.io.js' to 'http://' + location.hostname + ':3000/socket.io/socket.io.js'.
... "You might be wondering where the /socket.io/socket.io.js file
comes from, since we neither add it and nor does it exist on the filesystem. This is
part of the magic done by io.listen on the server. It creates a handler on the server
to serve the socket.io.js script file."
from the book Socket.IO Real-time Web
Application Development, page 56
You must just follow https://socket.io/get-started/chat/ and all will work.
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
http.listen(3000, function(){
console.log('listening on *:3000');
});
If you are following the socket.io tutorial https://socket.io/get-started/chat/, you should add this line as below.
app.use(express.static(path.join(__dirname, '/')))
This is because in the tutorial, Express will only catch the url
/ and send the file of index.html.
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html')
})
However, in the index.html, you have a script tag (<script src="/socket.io/socket.io.js"></script>) requests the resouce of socket.io-client, which is not routed in index.js (it can be found in console-network that the url is http://localhost:3000/socket.io/socket.io.js).
Please check the directory path mentioned in your code.By default it is res.sendFile(__dirname + '/index.html');
make sure you index.html in proper directory
Steps to debug
npm install socket.io --save in static files (index.html) for example, you may have installed it globally and when you look at the debugger, the file path is empty.
Change your script file and instantiate the socket explicitly adding your localhost that you have set up in your server file
<script src="http://localhost:5000/socket.io/socket.io.js"></script>
<script>
const socket = io.connect("localhost:5000");
$(() =>
Double check that the data is flowing by opening a new browser tab and pasting http://localhost:5000/socket.io/socket.io.js you should see the socket.io.js data
Double check that your server has been set-up correctly and if you get a CORs error npm install cors then add it to the server.js (or index.js whatever you have chosen to name your server file)
const cors = require("cors");
const http = require("http").Server(app);
const io = require("socket.io")(http);
Then use the Express middleware app.use() method to instantiate cors. Place the middleware this above your connection to your static root file
app.use(cors());
app.use(express.static(__dirname));
As a final check make sure your server is connected with the http.listen() method where you are assigning your port, the first arg is your port number, for example I have used 5000 here.
const server = http.listen(5000, () => {
console.log("your-app listening on port", server.address().port);
});
As your io.on() method is working, and your sockets data is connected client-side, add your io.emit() method with the callback logic you need and in the front-end JavaScript files use the socket.on() method again with the call back logic you require. Check that the data is flowing.
I have also edited a comment above as it was the most useful to me - but I had some additional steps to take to make the client-server connection work.
If you want to manually download "socket.io/socket.io.js" file and attaché to html (and not want to get from server runtime) you can use https://cdnjs.com/libraries/socket.io
like
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js" integrity="sha512-eVL5Lb9al9FzgR63gDs1MxcDS2wFu3loYAgjIH0+Hg38tCS8Ag62dwKyH+wzDb+QauDpEZjXbMn11blw8cbTJQ==" crossorigin="anonymous"></script>
while this doesn't have anything to do with the OP, if you're running across this issue while maintaining someone else's code, you might find that the problem is caused by the coder setting io.set('resource', '/api/socket.io'); in the application script, in which case your HTML code would be <script>type="text/javascript" src="/api/socket.io/socket.io.js"></script>.
If this comes during development. Then one of the reasons could be you are running a client-side file(index.html). But what you should do is run your server(example at localhost:3000) and let the server handle that static file(index.html). In this way, the socket.io package will automatically make
<script src="/socket.io/socket.io.js"></script> available on the client side.
Illustration(FileName: index.js):
const path = require('path');
const express = require('express');
const socketio = require('socket.io');
const port = 3001 || process.env.PORT;
const app = express();
const server = http.createServer(app);
const io = socketio(server);
//MiddleWares
app.use(express.json());
app.use(
express.urlencoded({
extended: false,
})
);
app.use(express.static(__dirname + '/public'));
app.get('/', (req, res) => {
res.sendFile('index.html');
});
io.on('connect', (socket) => {
console.log('New user joined');
}
server.listen(port, () => {
console.log(`App has been started at port ${port}`);
});
After this run your server file by the command
node index.js
Then open the localhost:${port}, Replace port with given in the index.js file and run it.
It solved my problem. Hope it solves yours too.

Categories