I'm new to Node and created an app that has some async/await syntax in it like so:
const express = require('express');
const app = express();
const someLibrary = require('someLibrary');
function asyncWrap(fn) {
return (req, res, next) => {
fn(req, res, next).catch(next);
};
};
app.post('/getBlock', asyncWrap(async (req,res,next) => {
let block = await someLibrary.getBlock(req.body.id);
[some more code]
}));
app.listen(process.env.PORT || 8000);
It works fine on my machine but when I deploy to Heroku I get an error because the syntax is not supported:
2017-03-23T10:11:13.953797+00:00 app[web.1]: app.post('/getBlock', asyncWrap(async (req,res,next) => {
2017-03-23T10:11:13.953799+00:00 app[web.1]: SyntaxError: Unexpected token (
What is the easiest way to get Heroku to support this syntax?
Specify the node version you want to use in your package.json: https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version
So for async/await support you'll want to specify >= 7.6.0
{
"engines": {
"node": ">= 7.6.0"
}
}
From the Heroku documentation here
https://devcenter.heroku.com/articles/getting-started-with-nodejs#declare-app-dependencies
it should be declared in your package.json file which engine(s) should be accessible:
{
"name": "node-js-getting-started",
"version": "0.2.5",
...
"engines": {
"node": "5.9.1"
},
"dependencies": {
"ejs": "2.4.1",
"express": "4.13.3"
},
...
}
Related
I am trying to deploy my first React.js app on Heroku. Everything seems to work fine link to app except the most important part - the Express.js REST API that I use to fetch data from my Postgres database and Stripe API is functioning normally on localhost, but when I deploy the app on Heroku, all the API routes I am trying to access return the same syntax error - Unexpected token < in JSON at position 0.
I understand that the issue is tied to how my app routes to the API. In other words, the fetch request is not able to get to the needed endpoint and thus return this syntax error, but I can't pinpoint exactly where is the issue - am I missing a '/' somewhere, have I incorrectly set up my environment variables, etc.?
Has someone had a similar issue or maybe someone can spot the issue in my code down below?
package.json
{
...
"private": true,
"main": "server.js",
"homepage": "https://dj-bbq.herokuapp.com",
"engines": {
"npm": "6.14.15",
"node": "14.18.1"
},
"dependencies": {
"#formspree/react": "^2.2.4",
"#stripe/react-stripe-js": "^1.7.0",
"#stripe/stripe-js": "^1.22.0",
"#testing-library/jest-dom": "^5.16.1",
"#testing-library/react": "^12.1.2",
"#testing-library/user-event": "^13.5.0",
"#userfront/react": "^0.2.22",
"cors": "^2.8.5",
"express": "^4.17.2",
"express-fileupload": "^1.2.1",
"helmet": "^5.0.1",
"jsonwebtoken": "^8.5.1",
"pg": "^8.7.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^6.2.1",
"react-scripts": "4.0.3",
"stripe": "^8.195.0",
"web-vitals": "^2.1.2"
},
"devDependencies": {
"dotenv": "^10.0.0",
"nodemon": "^2.0.15",
"source-map-explorer": "^2.5.2"
},
"scripts": {
"start": "node server.js",
"heroku-postbuild": "npm install && npm run build",
"dev-start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"analyze": "source-map-explorer 'build/static/js/*.js'",
"server": "node server.js",
"nodemon": "nodemon server.js"
},...
server.js
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const path = require('path'); // Allows to access files through the server in our filesystem
const fileUpload = require('express-fileupload'); // Parses multipart/form-data requests, extracts the files if available, and make them available under req.files property.
/**
** ------------- GENERAL SETUP -------------
*/
// Provides access to variables from the .env file by using process.env.REACT_APP_variable_name
require('dotenv').config();
const nodeEnv = process.env.NODE_ENV !== 'production';
const devPort = process.env.REACT_APP_server_dev_port;
const prodPort = process.env.PORT // process.env.PORT
const devDomain = process.env.REACT_APP_dev_domain;
const prodDomain= process.env.REACT_APP_prod_domain;
const PORT = nodeEnv ? devPort : prodPort;
const domain = nodeEnv ? devDomain : prodDomain;
// CORS options
const corsOptions = {
origin: domain, // frontend_URL for heroku deployment
credentials: true ,
// Allows only the following HTTP requests to go through
methods: [
"PUT",
"POST",
"DELETE",
"GET",
],
"Access-Control-Allow-Headers": [
"Origin",
"X-Requested-With",
"Content-Type",
"Accept",
"Authorization",
],
};
//* Creates the Express server instance as "app"
const app = express();
//* MIDDLEWARE
// Called BETWEEN processing the Request and sending the Response in your application method.
app.use(helmet()); // Sets many http headers to make them more secure
app.use(cors(corsOptions)); // To allow cross origin conections (Allows our React app to make HTTP requests to Express application)
// Instead of using body-parser middleware, use the new Express implementation of the same thing
app.use(express.json()); // To recognize the incoming Request Object (req.body) as a JSON Object
app.use(express.urlencoded({ extended: true })); // To recognize the incoming Request Object as strings or arrays
app.use(fileUpload({
createParentPath: true
})); // Enables file uploading
//* HEROKU MIDDLEWARE
if (process.env.NODE_ENV !== 'production') {
// To load static files or client files from here http://localhost:3000/images/kitten.jpg
app.use(express.static(path.join(__dirname, 'public')));
} else if (process.env.NODE_ENV === 'production') {
// Serve static files - makes the build folder accessible to app.
app.use(express.static(path.joins(__dirname, 'build')));
// app.use(express.static(path.resolve(__dirname, 'build')));
}
/**
** -------------- SERVER ----------------
*/
// Determines the PORT and enables LISTENing for requests on the PORT (http://localhost:8000)
app.listen(PORT, () => {
console.debug(`Server is listening at http://localhost:${PORT}`);
});
/**
** ------- ROUTES / ENDPOINTS ---------
*/
// Go to /test to make sure the basic API functioning is working properly
app.get('/test', (req, res) => {
res.status(200).send('The Basic API endpoints are working.')
});
// Imports all of the routes from ./routes/index.js
app.use(require('./app-server/routes/allRoutes'));
// If req comes from one of these domains (origins), then allow the request with CORS.
app.use((req, res, next) => {
const corsWhitelist = [
domain,
];
if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
}
next();
});
I have set-up a catch all route (router) for unkown routes in a different file
//* HEROKU - catch all for unrecognised routes
if (process.env.NODE_ENV === 'production') {
// Serve index.html file if it doesn't recognize the route
router.get('*', (req, res, next) => { // or * instead of /
res.sendFile(path.join(__dirname, 'build', 'index.html')); // resolve instead of join
})
}
And here is an example of a fetch request
const [recipes, setRecipes] = useState([]);
useEffect(() => {
let interval;
const fetchData = async () => {
try {
// const url = 'http://localhost:8000/recipes/display';
const url = `${customProxy}/recipes/display`;
const response = await fetch(url);
const json = await response.json();
setRecipes(json);
} catch(error) {
// console.error(error);
alert("Recipe displaying:" + error);
}
};
fetchData();
interval = setInterval(() => {
fetchData()
}, 86 * 1000)
return () => {
clearInterval(interval)
}
}, []); // Determine swhen to re-use useEffect, if this changes.
Thank you in advance for taking the time to consider the solution for issue!
Update 1
I started going through my project for the n-th time and previously I followed the guides found on Heroku to deploy my PERN app. The guides recommended using mars/create-react-app-buildpack to deploy the app, but after reading the documentation of this build pack it clearly says that this build pack is only meant for static react apps not react apps with its own custom node.js server.
In such cases, I am to use the mars/heroku-cra-node.
I have been following the documentation on how to set-up my folder structure, etc., but now, when I deploy the app, Heroku informs me of the following...
-----> Building on the Heroku-20 stack
-----> Using buildpacks:
1. https://github.com/mars/heroku-cra-node
-----> App not compatible with buildpack: https://github.com/mars/heroku-cra-node
bash: /tmp/codon/tmp/buildpacks/d07ae047a3685d9cfb39224105301a7dbdbfbe9c/bin/detect: No such file or directory
More info: https://devcenter.heroku.com/articles/buildpacks#detection-failure
! Push failed
I understand that the idea is that my folder structure is not as required by the build pack, but I am following its documentation by the letter.
Has anyone had any experience in using this build pack to deploy a PERN app to Heroku?
I noticed that this question of mine is still unanswered.
The issue, in the end, was that I was trying to use the Heroku free plan, but my app was too "big" for that so I either needed to split the back-end and front-end into two apps or to use a paid plan.
In the end, I actually changed my hosting service provider from Heroku to Digital Ocean. The app is still on their servers and works now - https://dj-bbq-i5gdc.ondigitalocean.app/ .
I created Next Js project. I deployed it to my CPanel. And I created server.js file on directory.
I called next module as require in server.js. But When I access to my website I catch an error.
internal/modules/cjs/loader.js:638
throw err;
^
Error: Cannot find module 'next';
This error message.
My server.js code
const { createServer } = require("http");
const { parse } = require("url");
const next = require("next");
const dev = process.env.NODE_ENV !== "production";
const port = !dev ? process.env.PORT : 3000;
// Create the Express-Next App
const app = next({ dev });
const handle = app.getRequestHandler();
app
.prepare()
.then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true);
const { pathname, query } = parsedUrl;
handle(req, res, parsedUrl);
console.log("pathname", pathname);
}).listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
})
.catch((ex) => {
console.error(ex.stack);
process.exit(1);
});
My package json
{
"name": "projectName",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
},
"dependencies": {
"express": "^4.17.1",
"next": "10.0.6",
"react": "17.0.1",
"react-dom": "17.0.1"
}
}
What should i do?
Thank you.
Best regards
Add this in your package.json dependency section : "#next/env": "^12.0.7"
I've already had problems publishing a next application other than on vercel. To fix the error I had to create a docker in order to publish the application. In case someone doesn't answer with a more viable solution, I recommend looking into using a docker.
I am trying to create a webservice using Express, which will be executable from the localhost as well as an AWS Lambda using Claudia.
I want to separate the app configuration and the app.listen function.
My app.ts file looks like this:
import express = require('express');
const dotenv = require('dotenv');
class App {
public app: express.Application = express();
constructor() {
dotenv.config();
// parse application/json request body to JSON Objects
this.app.use(express.json());
// parse x-ww-form-urlencoded request body to JSON Objects
this.app.use(express.urlencoded({ extended: true }));
this.app.get('/', (req, res) => {
res.send('API server is up and running');
});
}
}
module.exports = new App().app
Then, I am requiring the app in the local.ts file
const app = require('./app');
app.listen(process.env.PORT,
() => console.log(`Application is running on port ${process.env.PORT}`)
);
My package.json looks like this
{
"name": "nodejs-express-lambda",
"version": "1.0.0",
"description": "",
"main": "app.ts",
"scripts": {
"run": "npx ts-node local.ts",
"build": "tsc"
},
"author": "",
"license": "ISC",
"dependencies": {
"#types/dotenv": "^8.2.0",
"dotenv": "^8.2.0",
"express": "^4.17.1"
},
"devDependencies": {
"#types/express": "^4.17.6",
"#types/node": "^14.0.1",
"claudia": "^5.12.0",
"ts-node": "^8.10.1",
"tslint": "^6.1.2",
"typescript": "^3.9.2"
}
}
tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"target": "ES6"
},
"exclude": [
"node_modules",
]
}
Finally, running the npm run-script run will return
app.listen is not a function
Application is running on port 3000
I tried import app = require('./app') and it didn't work either. I am a bit lost in all those exports and imports, anybody can help ?
Running the app.listen from app.ts works fine.
I am not sure if this will help, but you may want to try this:
import express from 'express'
import dotenv from 'dotenv' // or just import 'dotenv/config'
class App {
public app: express.Application = express();
constructor() {
dotenv.config();
// parse application/json request body to JSON Objects
this.app.use(express.json());
// parse x-ww-form-urlencoded request body to JSON Objects
this.app.use(express.urlencoded({ extended: true }));
this.app.get('/', (req, res) => {
res.send('API server is up and running');
});
}
}
const app = new App().app
export default app
and in second file
import app from './app'
I am currently building a simple CRUD app using ExpressJS, and host it on Heroku using free account.
The problem I ran into is:
GET API for getting all items works on localhost, but show status 503 when hosting on Heroku;
POST API for updating one item works on localhost, but same issue as GET API above;
All 503 errors are after 30s of loading, this should be a setting from Heroku.
I do have other API end points that work on both local and Heroku server:
GET API for getting one item using ID
My guessing:
The issue should not be a code issue
There is some issue when the code is deployed and Heroku cannot process this request
I tried to find some articles on the web but this seems hard to diagnose, anyone who has experience please let me know how I can solve this issue. Appreciate your comments.
My Mongoose Schema
const mongoose = require("mongoose");
const ThoughtSchema = mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model("Thought", ThoughtSchema);
2 end points that do not work
// Returns all thoughts
router.get("/", async (req, res) => {
try {
const thought = await Thought.find();
res.json(thought);
} catch (err) {
res.json({ message: err });
}
});
// Submit a post
router.post("/", async (req, res) => {
const thought = new Thought({
title: req.body.title,
content: req.body.content
});
try {
const savedThought = await thought.save();
res.json(savedThought);
} catch (err) {
res.json({ message: err });
}
});
The end point that works
// Specific thought
router.get("/:thoughtId", async (req, res) => {
try {
const thought = await Thought.findById(req.params.thoughtId);
res.json(thought);
} catch (err) {
res.json({ message: err });
}
});
My package.json for this express app
{
"name": "my-thoughts-app",
"version": "0.1.0",
"description": "An app to records user's thoughts",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/PayneTang/my-thoughts-app.git"
},
"author": "Payne Tang",
"license": "ISC",
"bugs": {
"url": "https://github.com/PayneTang/my-thoughts-app/issues"
},
"homepage": "https://github.com/PayneTang/my-thoughts-app#readme",
"dependencies": {
"dotenv": "^8.2.0",
"express": "^4.17.1",
"mongoose": "^5.8.11"
},
"devDependencies": {
"typescript": "^3.7.5"
}
}
EDIT:
My index.js
const express = require("express");
const path = require("path");
const app = express();
const mongoose = require("mongoose");
const thoughtRoute = require("./routes/thought");
require("dotenv").config();
console.log(process.env);
// Mongoose settings
mongoose.connect(
process.env.DB_CONNECTION,
{ useNewUrlParser: true, useUnifiedTopology: true },
() => {
console.log("Connected to DB!");
}
);
app.use(express.json());
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
app.use("/api/thought", thoughtRoute);
app.get("/api/test", (req, res) => {
res.send("hi");
});
// Serve client side
app.use(express.static(path.join(__dirname, "client/build")));
app.use(express.static(path.join(__dirname, "client/public")));
// app.get("*", (req, res) => {
// res.sendFile(path.join(__dirname, "client/build/index.html"));
// });
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log("Listening on port " + PORT + "...");
});
The root cause after checking is due to the access restriction from Heroku to Mongo atlas.
After adding 0.0.0.0/0 for IP whitelist, I am able to get data from MongoDB.
Reference: https://docs.atlas.mongodb.com/security-whitelist/#add-whitelist-entries
I had the same problem and I was able to fix it by doing these two steps:
Add node version to package.json file:
"engines": {
"node": "14.17.3"
}
}
I changed access settings in MongoDB, allowing access to the database from anywhere (basically, whitelisting 0.0.0.0/0 IP address)
In my case, the issue was in package.json I installed two new packages yesterday and in my package.json:
"engines": {
"node": "12.16.0"
},
I changed the version to the my current system version:
"engines": {
"node": "14.5.0"
},
this is how my 503 service unavailable error gone.
This can be caused in several ways to the Node app.
1- Make sure that you specify the right port as what heroku does is it runs our app on a dynamic port.
const PORT = process.env.PORT || 3000;
app.listen(PORT, err => {
if(err) throw err;
console.log("%c Server running", "color: green");
});
as described in this comment
https://stackoverflow.com/a/52992592/11887902
2- Make sure that you added the Procfile with
npm start
to start the application.
3- If you are using Nodemon and you install it globally, just make sure that you install it locally too.
Finally, just have a look at the logs of the project to figure what heppen to make your project not in the service.
These cases happened to me and caused this error.
My issue was caused due to case sensitivity that is at times ignored by node,
in my controllers I had a file named sessions.js yet when importing in my routes I had mistakenly put ... = require('../controllers/Sessions'),
Nodemon was running without issues as I was developing but upon deploying on heroku it crashed so I changed to ... = require('../controllers/sessions')
and now it runs ok
I'm taking an online course on writing block-chain from scratch.
The course utilizes javascript and node.js.
I am very new to these technologies but followed the course so far to the T.
i'm pasting the relevant code - the app file (index):
const express = require('express');
const bodyParser = require('body-parser');
const Blockchain = require('../blockchain');
const P2pServer = require('./p2p-server');
const HTTP_PORT = process.env.HTTP_PORT || 3001;
const app = express();
const bc = new Blockchain();
const p2pServer = new P2pServer(bc);
app.use(bodyParser.json());
app.get('/blocks', (req, res) => {
res.json(bc.chain);
});
app.post('/mine', (req, res) => {
const block = bc.addBlock(req.body.data);
console.log(`New blovk added: ${block.toString()}`);
res.redirect('/blocks');
});
app.listen(HTTP_PORT, () => console.log(`Listening on port ${HTTP_PORT}`));
p2pServer.listen();
and the code from p2p-server.js:
const Websocket = require('ws');
const P2P_PORT = process.env.P2P_PORT || 5001;
const peers = process.env.PEERS ? process.env.PEERS.split(',') : [];
//HTTP_PORT=3002 P2P_PORT=5003 PEERS=ws://localhost:5001 npm run dev
class P2pServer {
constructor(blockchain) {
this.blockchain = blockchain;
this.sockets = [];
}
listen() {
const server = new Websocket.Server({ port: P2P_PORT });
server.on('connection', socket =>this.connectSocket(socket));
this.connectToPeers();
console.log(`listening to peer-to-peer connections on: ${P2P_PORT}`);
}
connectToPeers() {
peers.forEach(peer => {
const socket = new Websocket(peer);
socket.on('open', () => this.connectSocket(socket));
});
}
connectSocket(socket){
this.sockets.push(socket);
console.log('socket connected');
}
}
module.exports = P2pServer;
when I try to run the following in the command line:
HTTP_PORT=3002 P2P_PORT=5003 PEERS=ws://localhost:5001 npm run dev
I get the following:
'HTTP_PORT' is not recognized as an internal or external command, operable program or batch file.
for some reason the process.env isn't picking up the input and passing it on to the app. What is wrong here?
Thanks!
EDIT: I was asked to add the package.json:
{
"name": "sf-chain",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest --watchAll",
"dev-test": "nodemon dev-test",
"start": "node ./app",
"dev": "nodemon ./app"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"jest": "^23.1.0",
"nodemon": "^1.17.5"
},
"dependencies": {
"body-parser": "^1.18.3",
"crypto-js": "^3.1.9-1",
"express": "^4.16.3",
"ws": "^5.2.0"
}
}
You are using:
$ HTTP_PORT=3002 P2P_PORT=5003 PEERS=ws://localhost:5001 npm run dev
It is showing an error, because the window powershell will not recognize this command..
Instead you should use:
set HTTP_PORT=3002 && set P2P_PORT=5002 && set PEERS=ws://localhost:5001 && npm run dev
I believe were doing the same course. I'm sure you've probably figured this out but I tried the same step in Git Bash instead of Powershell and it worked.