Deploy Node.js RestFull API to Heroku - node.js

I have a school assignment where i must build a node.js server (Without Express) that receives a POST request containing {day: 25, month:12, year:2017} and sends the number of days remaining to that date.
I was able to solve this using moment npm package (https://www.npmjs.com/package/moment)
The server is listening on port 3000.
The code works perfectly when i send a post request to 127.0.0.1:3000
However, i changed listen port to 80, created a new app on heroku and then deployed my code and it doesn't work anymore, heroku says application crash.
Does anyone have an idea ?
server is created like this :
var http = require('http');
var moment = require('moment');
moment().format();
var server = http.createServer(function(request, response) {
....
});
server.listen(80);

Heroku uses the process.env of nodeJS. In order to make sure your app works on heroku you should set the an variable called port that takes either port 3000 / 80 for local app and process.env.PORT for heroku deployments.
const port = process.env.PORT || 3000
Hope that helped!

Related

Accessing Express server on EC2

I'm using Express on my Amazon EC2 server. My server looks like this:
var express = require('express');
var app = express();
app.get('/my_view/true', function (req, res) {
//do something
res.render('view', {var1: somevalue});
});
app.listen(3000);
When I access my Express app locally using http://localhost/view/true, it works and I get my template displayed in browser.
But when I try use it on EC2 via ec2-myinstance.us-east-2.compute.amazonaws.com/view/true I get This site can’t be reached. refused to connect error.
I've added HTTP 80 port in my AWS EC2 Security Group settings but it's still not working.
Can someone help?
You should set the server to listen at port 80, instead you are listening at port 3000. So either open up the port 3000 in the security group or listen at the port 80.
app.listen(80);
The above change should work. Let me know if it works.

heroku send request from a front-end app to a back-end one

I created an hapi.js backend app on heroku. After a bunch of problems all works well. Now, I want to create a frontend app with react.js, but I have a problem:
const server = Hapi.server({
port: process.env.PORT,
host: '0.0.0.0'
});
To define the port of the backend I've the enviroment variable, so I don't really know its value. So how can the react app knows the correct port of the server where to connect?
You actually don't need to know the port number. You can use the default port which is 80 for HTTP and 443 for HTTPS.
According to the heroku docs:
The contract with Heroku is for the process to bind to a port to serve requests. Heroku’s routers are then responsible for directing HTTP requests to the process on the right port.
Which means heroku listens to port 80 for HTTP and port 443 for HTTPS by itself.
References:
https://devcenter.heroku.com/articles/runtime-principles#web-servers
https://stackoverflow.com/a/51572239/5045878
https://stackoverflow.com/a/54200996/5045878
I would say you don't need to know the port because all your requests will be done to https://hapi.yourdomain.com, and your front will be served to https://yourdomain.com
Edit:
In heroku this is how you define the port:
const port = process.env.PORT || 8000
Heroku will provide the environment variable you need (that changes every time you deploy your app)
Then your react app don't need to connect to a specific port, just access your endpoints like this :
https://back.domain.com/your/endpoint

How to run two servers on Heroku?

I have built a project in Angular 9 for the frontend and Node.js as the backend server.
Now I am running node appserver.js for running the backend server. This listens to port 9090 as default. In another terminal, I am running ng serve to run my Angular app on port 4200 as usual. I have a service in the Angular app that sends and receives messages from server.
I have used WebSocket class to connect to the port 9090. My app works fine in local. But now how could I deploy in Heroku. Heroku gives a random port number which will be specified as process.env.PORT. how could I get that port in my WebSocket service?
My questions are:
How to deploy two servers in Heroku?
How port number in appserver.js is specified as port number in WebSocket service in Angular?
Is there any use of the .env file and ProcFile to solve my problem?
Is there any use of multi-buildpack which is in Heroku to solve my problem?
You cannot deploy two separate servers when they each require a port. You will have to put them into separate apps. In some cases you can combine web servers. Deploying a server is done as regular.
When deploying a web service on Heroku Heroku provides you a port to which you have to bind to. You can then visit your web service under <appname>.herokuapp.com. (<-- this is why 1.) requires you to put them into separate apps.). Furthermore when you connect to the webservice you merely give the URL. That URL is automatically translated into <ipaddress>:<port>. So in your frontend you are not going to specify a port number. You are specifying the websocket URL in your frontend without any port.
In your web server you bind to process.env.PORT.
.env file shouldn't be versioned/committed. No use. If you require environment variables you can set them through Heroku's dashboard. Procfile is not required since you are using Node.js it will look into your npm start script located in package.json. But it doesn't hurt to have since it gives clarity.
There is no multi-buildpack for this.
If your 2 servers are strictly distinct and use separate protocols. One using http, the other ws you can bundle your two servers into one. Here is an example:
const http = require('http');
const path = require('path');
const express = require('express');
const WSServer = require('ws').Server;
const DateFormat = require('dateformat');
let wss;
let server;
const app = express();
app.use(express.static(path.join(__dirname, './../build')));
server = new http.createServer(app);
wss = new WSServer({ server })
this.wss = wss;
wss.on('connection', function(socket) {
console.log(DateFormat(new Date(), 'm/d h:MM:ss TT'),
`client connected to server (${wss.clients.size} total)`);
socket.on('message', function(data) {
console.log(data)
});
socket.on('close', function(code, desc) {
console.log(DateFormat(new Date(),
"h:MM:ss TT"),'client disconnected, total:', wss.clients.length);
});
});
wss.on('listening', () => console.log('Websocket listening on port', config.get('port')));
wss.on('error', err => console.log('Websocket server error:', err));
server.on('error', err => console.log('Server error:', err));
server.listen(process.env.PORT);
Example in a project:
https://github.com/vegeta897/d-zone/blob/63730fd7f44d2716a31fcae55990d83c84d5ffea/script/websock.js
In the project the backend with the websocket server was extended to include an express server serving the static files. Note that this change only exists in the heroku branch.
You will find all the relevant changes that made that project heroku compatible in this commit:
https://github.com/vegeta897/d-zone/commit/63730fd7f44d2716a31fcae55990d83c84d5ffea

Host a Node.js bot (express and botkit)

I just made a bot in node.js for the Cisco Webex Teams application. My bot uses "express" and "botkit". "Express" requires listening on the port "3000" and "Botkit" listening on the port "8080".
I tried heroku.com but it does not accept two predefined ports and does not save files dynamically (fs.write)
var PUBLIC_URL = "http://a796e3b7.ngrok.io";
var port ='3000';
var ACCESS_TOKEN ='xxx';
var SECRET = "xxx";
var express = require('express');
var app = express();
var Botkit = require('botkit');
var controller = Botkit.webexbot({
log: true,
public_address: PUBLIC_URL,
access_token: ACCESS_TOKEN,
secret: SECRET,
webhook_name: process.env.WEBHOOK_NAME || 'Email2Webex',
});
controller.setupWebserver(8080, function(err, webserver) {
controller.createWebhookEndpoints(webserver, bot, function() {
console.log("Webhooks set up!");
});
});
app.post('/mailgun', upload.any(),function(req, res, next){
res.end('ok');
});
app.listen(port);
Currently I use ngrok to host the bot locally on my computer and I want to be able to host it on a server so I do not have to worry about it. how can I do ?
You can't set the port on Heroku apps. Heroku sets the port you're supposed to use through the PORT environment variable, and you should use it via process.env.PORT. Generally speaking, deployed applications should not run on development ports like 8080 - if it's an HTTP server, it must listen on port 80, for example.
In order to have two apps listening at the same time, I suggest you refactor your code and include both your bot and your app into a single express server that will listen at the port defined by Heroku's PORT environment variable.
Concerning access to the file system, it is borderline possible to use it, but there are high security restrictions, so a code that might run on your machine is likely to break on the server. Generally speaking it's a bad idea to access the file system directly in Heroku, except for read-only actions on deployed files. That is in part because the file system is ephemeral, so dont assume your written files will always be there. Most issues related to the caveats of using the file system can be resolved by using database or file storage features provided by Heroku, though.

Trying to proxy with Node and express-http-proxy and failing

I'm launching NPM express in a very simple app and wanting to take what is passed into the URL and redirect it as follows. Assuming I'm listening for web traffic on 8080 and I want to proxy my rest calls to port 5000.
That is, when the URL http://localhost:3077/rest/speakers comes in, I want the results to come from http://localhost:5000/rest/speakers (where the word speakers could be sessions, attendees or any other name like that.
app = express();
app.use('/rest', proxy('http://localhost:5000/rest'));
app.listen(8080, function () {
console.log('Listening on port 8080');
});
I seem to get the result of localhost:5000 but not even sure of that.
I changed to using http-proxy-middleware and this solved my problem.
app = express();
const proxy = require("http-proxy-middleware");
const targetVal = 'http://localhost:5000/rest';
app.use(proxy('/rest', {target: process.env.DEV_RESTURL, changeOrigin:true}));

Resources