Expressjs cors issue when fetching from different origin - javascript

So im using express as a simple backend for my client application. When trying to make a request to the endpoint GET /urls below it keep getting this message.
Access to fetch at 'http://localhost:5000/urls' from origin 'http://localhost:3000' has been
blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested
resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to
fetch the resource with CORS disabled.
My express server looks like so
require("dotenv/config");
const express = require("express");
var bodyParser = require("body-parser");
const app = express();
const cors = require("cors");
const mongoose = require("mongoose");
const ShortUrl = require("./modules/shortUrl");
var whitelist = ['http://localhost:3000']
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.use(cors());
app.use(express.urlencoded({ extended: false }));
app.use(bodyParser.json());
mongoose
.connect(process.env.MONGO_DB_CONNECTIONSTRING, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log("\nConnected to Mongo Database\n"));
app.get("/urls", cors(corsOptions), async (req, res) => {
const shortUrls = await ShortUrl.find();
res.send({ serverBaseUrl: process.env.SERVER_BASE_URL, shortUrls });
});
app.post("/url", cors(corsOptions), async (req, res) => {
console.log(req.body);
await ShortUrl.create({ full: req.body.fullUrl });
res.send();
});
app.get("/:shortUrl", cors(corsOptions), async (req, res) => {
const url = await ShortUrl.findOne({ short: req.params.shortUrl });
if (url === null) return res.sendStatus(404);
url.clicks++;
await url.save();
res.redirect(url.full);
});
app.listen(process.env.PORT || 5000);
In my web application I'm using a fetcher, I quickly typed up so it could be something in there which isnt quite right.
const createFetchOptions = (method, body = undefined) => {
const options = {
method,
headers: {}
};
if (body && body instanceof FormData) {
options.body = body;
} else if (body) {
options.headers["Content-type"] = "application/json";
options.body = JSON.stringify(body);
}
return options;
};
const Fetcher = {
get: async url => {
const res = await fetch(url, createFetchOptions("GET"));
return res;
},
post: async (url, body) => {
const res = await fetch(url, createFetchOptions("POST", body));
return res;
}
};
export default Fetcher;
This is a copy of my package,json incase its todo with a version issue
{
"name": "url_shortner",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "nodemon server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"ejs": "^3.0.1",
"express": "^4.17.1",
"mongoose": "^5.9.4",
"shortid": "^2.2.15"
},
"devDependencies": {
"nodemon": "^2.0.2"
}
}
Any help would be appreciated,
Chris.

When you use app.use(cors()); it becomes middleware for all requests. Therefore, you don't need to manually add it to your routes. If you want to whitelist one particular domain for all routes, then you can utilize the origin option (I set it as a process string variable to be more flexible for development and production environments):
const { CLIENT } = process.env;
app.use(
cors({
origin: CLIENT, // "http://localhost:3000" for dev and "https://example.com" for production
})
);

Related

CORS errors after deployment to render, worked fine locally

like the title says, here is my server file, I have tried every solution I could find on google yet I am still getting CORS errors. specifically XHROPTIONShttps://slug-panel-api.onrender.com/login
server.js:
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser')
const mongoose = require('mongoose')
const userSchema = require('../../SlugAPI/Schemas/SlugSchemas')
const divisionSchema = require('../src/SlugSchemas/DivisionSchemas/DivisionSchema')
const subDivisionSchema = require('../src/SlugSchemas/DivisionSchemas/SubDivisionSchema')
const teamSchema = require('../src/SlugSchemas/DivisionSchemas/TeamSchema')
const divisionMemberSchema = require('../src/SlugSchemas/DivisionSchemas/DivisionMemberSchema')
let CryptoJS = require('crypto-js')
const PORT = process.env.PORT || 8080;
const app = express();
app.use(cors({
origin: "https://slug-panel.onrender.com",
headers: {
"Access-Control-Allow-Origin": "https://slug-panel.onrender.com",
"Access-Control-Allow-Credentials": true
},
}));
mongoose.set("debug")
const usar_db = mongoose.createConnection("mongodb:/<username>:<password>#slug-db:27017/usarAdmin?authSource=admin");
const User = usar_db.model('User', userSchema)
const Division = usar_db.model('Division', divisionSchema)
const SubDivision = usar_db.model('SubDivision', subDivisionSchema)
const Team = usar_db.model('Team', teamSchema)
const DivisionMember = usar_db.model('Division_Member', divisionMemberSchema)
function generateUserRegistrationKey(username, discord_id, rank, authentication_level) {
let key = username + '/' + discord_id.toString() + '/' + rank + '/' + authentication_level
const ciphertext = CryptoJS.AES.encrypt(key, 'secret').toString()
return ciphertext
}
function decryptUserRegistrationKey(key) {
const bytes = CryptoJS.AES.decrypt(key, 'secret')
const originalText = bytes.toString(CryptoJS.enc.Utf8)
return originalText
}
app.post('/login', bodyParser.json(), async (req, res, next) => {
const user = req.body.username
let pw = req.body.password
pw = CryptoJS.SHA256(pw)
let exists = await User.findOne({username: user})
if (exists) {
if (pw.toString() === exists['password']) {
res.send({
token: 'test123'
})
} else {
res.send({
error: 'passwordNotFound'
})
}
} else {
res.send({
error: 'userNotFound'
})
}
});
app.post('/generate', bodyParser.json(), async function (req, res, next) {
let username = req.body.username
let discord_id = req.body.discord_id
let rank = req.body.rank
let authentication_level = req.body.authentication_level
let exists = await User.exists({discord_id: discord_id})
let regKey = generateUserRegistrationKey(username, discord_id, rank, authentication_level)
const newUser = User({
username: username,
discord_id: discord_id,
rank: rank,
regKey: regKey,
authentication_level: authentication_level,
})
if (!exists) {
newUser.save()
.then(r => console.log("User " + username + " added to db"))
res.send({regKey: regKey})
}
})
app.post('/register', bodyParser.json(), async function (req, res, next) {
let key = req.body.regKey
let pw = CryptoJS.SHA256(req.body.password).toString()
let decryptedKey = decryptUserRegistrationKey(key).split('/')
let exists = await User.find({regKey: key}, function(err, docs) {
if (err) {
console.log(err)
} else {
console.log('Result: ', docs)
console.log(pw)
}
}).clone()
if (!exists) {
res.send({user: null})
} else {
res.send(JSON.stringify(exists))
}
await User.findOneAndUpdate({regKey: key}, { is_registered: true, password: pw, authentication_level: decryptedKey[decryptedKey.length - 1]})
})
app.post('/createDivision', bodyParser.json(), async function (req, res, next) {
let div_name = req.body.division_name
let div_id = req.body.division_id
let exists = await Division.findOne({division_name: div_name}, function (err, docs) {
if (err) {
console.log(err)
} else {
console.log(docs)
}
}).clone()
let idexists = await Division.findOne({division_id: div_id}, function (err, docs) {
if (err) {
console.log(err)
} else {
console.log(docs)
}
}).clone()
if (!exists || !idexists) {
const newDivision = new Division({
division_name: div_name,
division_id: div_id
})
newDivision.save()
.then(() => console.log('Division ' + div_name + ' has been added to the db'))
res.send(JSON.stringify(newDivision))
} else {
res.send({errorcode: 420})
}
})
app.post('/createSubDivision/:divid', bodyParser.json(), async function (req, res, next) {
const division = req.params['divid']
const sub_name = req.body.subdivision_name
const sub_id = req.body.subdivision_id
let exists = await Division.findOne({division_id: division}, function (err, docs) {
if (err) {
console.log(err)
} else {
console.log(docs)
}
}).clone()
if (exists) {
let subdivid_exists = await Division.findOne({
division_id: division,
subdivisions: {
$elemMatch: {subdivision_id: sub_id}
}
})
let subdiv_exists = await Division.findOne({
division_id: division,
subdivisions: {
$elemMatch: {subdivision_name: sub_name}
}
})
if (!subdivid_exists || !subdiv_exists) {
const subDiv = new SubDivision({
subdivision_name: sub_name,
subdivision_id: sub_id,
})
await Division.findOneAndUpdate({division_id: division}, { $push: {subdivisions: subDiv}})
console.log('subdivision ' + sub_name + ' added to: ' + exists.division_name)
res.send(JSON.stringify(subDiv))
} else {
res.send({division:'exists'})
}
}
})
app.listen(PORT, () => console.log('API is running on ' + PORT));
Tried every solution I could find both on random google websites and on stackoverflow. as stated previously it worked fine on the development server hosted locally.
for reference, here is how I am using fetch throughout the frontend
async function loginUser(credentials) {
return fetch('https://slugga-api.onrender.com/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': 'true'
},
body: JSON.stringify(credentials)
})
.then(data => data.json())
}
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://slugga-api.onrender.com/login. (Reason: CORS request did not succeed). Status code: (null).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://slugga-api.onrender.com/login. (Reason: CORS request did not succeed). Status code: (null).
Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource. asyncToGenerator.js:6:4
Babel 6
c Login.js:20
React 11
bind_applyFunctionN self-hosted:1683
Wt self-hosted:1640
React 3
forEach self-hosted:4909
React 2
<anonymous> index.js:7
<anonymous> index.js:17
<anonymous> index.js:17
You're misusing those CORS headers, both on the client side and on the server side. You should familiarise better with CORS and with the API of Express.js's CORS middleware.
Client side
The Access-Control-Allow-Origin header is a response header; including it in a request makes no sense.
async function loginUser(credentials) {
return fetch('https://slugga-api.onrender.com/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': 'true' // incorrect
},
body: JSON.stringify(credentials)
})
.then(data => data.json())
}
Server side
The headers property of your CORS config corresponds to request headers that you wish to allow, but what you've listed are response headers.
app.use(cors({
origin: "https://slug-panel.onrender.com",
headers: {
"Access-Control-Allow-Origin": "https://slug-panel.onrender.com", // incorrect
"Access-Control-Allow-Credentials": true // incorrect
},
}));
Instead, you most likely want something like
app.use(cors({
origin: "https://slug-panel.onrender.com",
headers: ["Content-Type"],
credentials: true,
}));
Fixed the issue by changing the CORS initialization in server.js
const app = express();
app.use(cors({
origin: "https://slug-panel.onrender.com"
}
))
app.options('*', cors())

Axios POST to Heroku is blocked by CORS - Network Error: 503

I'm using MERN Stack and everything was working fine until I made some changes to the UI (Moving code to different components, changing styles,...).
I didn't change any code in the Axios request and only this POST request doesn't work, the other requests work normally.
I have already setup CORS in my backend
I can access my-project.herokuapp.com/insert link and there's no error in the Heroku logs. No error thrown in the client or server terminal.
When I click on the Add To List button in the form, the addToList function which contains the Axios POST request doesn't send the data to the database like it used to.
After 30 seconds - this error appears:
Please help me understand what is going on and how to fix this. I have looked for other solutions but I don't know how to apply to my case.
Thank you! :)
Here's my code:
addToList function on the client-side:
const [foodName, setFoodName] = useState('')
const [isVegetarian, setIsVegetarian] = useState('')
const [priceRange, setPriceRange] = useState('$')
const [foodUrl, setFoodUrl] = useState('')
const [foodList, setFoodList] = useState([])
const addToList = async (event) => {
event.preventDefault()
try {
await Axios.post(
"https://my-project.herokuapp.com/insert",
{
foodName: foodName,
isVegetarian: isVegetarian,
priceRange: priceRange,
foodUrl: foodUrl,
}
)
.then(() => {
setFoodName('')
setIsVegetarian('')
setPriceRange('$')
setFoodUrl('')
})
} catch(err) {
console.error(`The error is ${err}`)
}
}
Dinner.js - Mongoose Schema
const mongoose = require('mongoose')
const DinnerSchema = new mongoose.Schema({
foodName: {
type: String,
required: true,
},
isVegetarian: {
type: String,
required: true,
},
priceRange: {
type: String,
required: true,
},
foodUrl: {
type: String,
required: true,
}
})
const Dinner = mongoose.model("dinners", DinnerSchema)
module.exports = Dinner
Server's index.js and the endpoint that doesn't work:
const express = require("express")
const mongoose = require("mongoose")
const cors = require('cors')
const app = express()
require("dotenv").config()
const DinnerModel = require('./models/Dinner')
app.use(express.json())
app.use(cors())
// Connect to MongoDB
mongoose.connect(
'mongodb+srv://linktoDB',
{
useNewUrlParser: true,
}
)
// Create:
app.post("/insert", async (req, res) => {
const foodName = req.body.foodName
const isVegetarian = req.body.isVegetarian
const priceRange = req.body.priceRange
const foodUrl = req.body.foodUrl
const dinner = new DinnerModel(
{
foodName: foodName,
isVegetarian: isVegetarian,
priceRange: priceRange,
foodUrl: foodUrl
}
)
try {
await dinner.save()
res.send("Inserted successfully")
} catch(err) {
console.log(err)
}
})
// Creating a port:
app.listen(process.env.PORT || 3001, () => {
console.log("Server is connected.")
})
My backend's package.json:
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"engines": {
"node": "12.20.1"
},
"scripts": {
"start": "node index.js",
"devStart": "nodemon index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.2",
"mongoose": "^6.1.3",
"nodemon": "^2.0.15",
"validator": "^13.7.0"
}
}
UPDATE 1
I added this code and it still doesn't work:
const corsOptions = {
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204,
}
app.use(cors(corsOptions))
Here's the preflight request and response when I try to add the document. One with status 204 and one with status 503:
https://i.stack.imgur.com/v1IcS.png
https://i.stack.imgur.com/AzH8d.png
UPDATE 2
I found out what the problem is when I check the payload. Please check my answer below.
Thanks everyone for helping me with this!
I have found what caused the 503 Error when checking for the Payload of the POST request in the Network tab.
It was receiving an empty string for my isVegetarian value.
That empty string happened because I changed the isVegetarian schema type from Boolean to String but forgot to change the initial state to a specific value:
const [isVegetarian, setIsVegetarian] = useState('')
In the Schema, I set isVegetarian to required: true so it won't accept empty strings.
-> So if you have the CORS config right and still have the same 503 error. Maybe check for the Network tab for preflight requests, response & payload to see if there's any leftover code you need to review.

Using Node.js to generate dynamic word document using Database value

I am trying to dynamically populate the WORD Document using npm docx. I am trying to read the data from the SQLite database but due to async node js property the values are not getting into the variable and it shows undefined. If I make the function synchronous the npm docx throws error and doesn't populate the document.
package.json
{
"name": "demoName",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"docx": "^5.1.1",
"express": "^4.17.1",
"md5": "^2.2.1",
"sqlite3": "^4.2.0"
}
}
index.js
const docx = require('docx');
var express = require('express');
var app = express();
var db = require("./database.js")
var bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const { AlignmentType, Document, Footer, Header, HeadingLevel, Packer, Paragraph, TextRun, UnderlineType, Table, TableCell, TableRow } = docx;
app.get("/doc", async(req, res) => {
var sql = "select * from DocDetails"
var params = []
//let DocDetailsData;
//let DocDetailsData = [{docId: "Some Doc Id"}];
const DocDetailsData = db.all(sql, params, (err, rows) => {
if (err) {
res.status(400).json({"error":err.message});
return;
}
console.log(rows[0]);
return rows[0];
});
console.log(DocDetailsData.docId);
const doc = new Document();
doc.addSection({
children: [
new Paragraph({
children: [
new TextRun({
text: "DEMO TEST DOCUMENT"
}),
new TextRun({
text: DocDetailsData.docId,
}),
]
}),
],
});
const b64string = await Packer.toBase64String(doc);
res.setHeader('Content-Disposition', 'attachment; filename=My Document.docx');
res.send(Buffer.from(b64string, 'base64'));
});
madeDoc = function(){
}
app.use(function(req, res){
res.status(404);
});
var server = app.listen(4041, function () {
var host = 'localhost'
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
database.js
var sqlite3 = require('sqlite3').verbose()
var md5 = require('md5')
const DBSOURCE = "db.sqlite"
let db = new sqlite3.Database(DBSOURCE, (err) => {
if (err) {
// Cannot open database
console.error(err.message)
throw err
}else{
console.log('Connected to the SQLite database.')
db.run(`CREATE TABLE DocDetails (
id INTEGER PRIMARY KEY,
docId text NOT NULL,
version float NULL,
editedBy text NULL,
editedDate text NULL,
effectiveDate text NULL)`,
(err) => {
if (err) {
// Table already created
console.log('Table not created');
}else{
console.log('Table created');
var insert = 'INSERT INTO DocDetails (docId, version, editedBy, editedDate, effectiveDate) VALUES (?,?,?,?,?)'
db.run(insert, ["NESS-RD-TEMP-EDCHB",2.1, "manab", "18-Jul-2017", "18-Jul-2020"])
}
})
}
});
module.exports = db
If you go to localhost:4041/doc, a word document should get downloaded but it shows only one row and not the data from database. I need the database value to be populated in the doc.
Thanks.
In order for this example to work, you need to understand how to work with asynchronous execution and callbacks. You cannot return anything from the callback and get it in the DocDetailsData variable as it would in synchronous code, because when you call the db.all method, the code continues to execute further, without waiting for the callback that you passed to it to work. Instead, you need to put the code for generating the doc file in the callback and do it in it. I hope that at least I could explain to you how it works. This is how your code will work correctly:
index.js
const docx = require('docx');
var express = require('express');
var app = express();
var db = require("./database.js")
var bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const { AlignmentType, Document, Footer, Header, HeadingLevel, Packer, Paragraph, TextRun, UnderlineType, Table, TableCell, TableRow } = docx;
app.get("/doc", async (req, res) => {
var sql = "select * from DocDetails"
var params = []
db.all(sql, params, async (err, rows) => {
if (err) {
res.status(400).json({"error":err.message});
return;
}
const DocDetailsData = rows[0];
const doc = new Document();
doc.addSection({
children: [
new Paragraph({
children: [
new TextRun({
text: "DEMO TEST DOCUMENT"
}),
new TextRun({
text: DocDetailsData.docId,
}),
]
}),
],
});
const b64string = await Packer.toBase64String(doc);
res.setHeader('Content-Disposition', 'attachment; filename=My Document.docx');
res.send(Buffer.from(b64string, 'base64'));
});
});
app.use(function(req, res){
res.status(404);
});
var server = app.listen(4041, function () {
var host = 'localhost'
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
});
database.js does not require changes

Express.js Csurf working in postman but not React.js

I'm trying to setup CSRF tokens so that I can do a number of checks before issueing a token to the client to use in future requests.
Taking the guidance from the csurf documentation, I've setup my express route with the following:
const express = require('express');
const router = express.Router({mergeParams: true});
const csurf = require('csurf');
const bodyParser = require('body-parser');
const parseForm = bodyParser.urlencoded({ extended: false });
const ErrorClass = require('../classes/ErrorClass');
const csrfMiddleware = csurf({
cookie: true
});
router.get('/getCsrfToken', csrfMiddleware, async (req, res) => {
try {
// code for origin checks removed for example
return res.json({'csrfToken': req.csrfToken()});
} catch (error) {
console.log(error);
return await ErrorClass.handleAsyncError(req, res, error);
}
});
router.post('/', [csrfMiddleware, parseForm], async (req, res) => {
try {
// this returns err.code === 'EBADCSRFTOKEN' when sending in React.js but not Postman
} catch (error) {
console.log(error);
return await ErrorClass.handleAsyncError(req, res, error);
}
});
For context, the React.js code is as follows, makePostRequest 100% sends the _csrf token back to express in req.body._csrf
try {
const { data } = await makePostRequest(
CONTACT,
{
email: values.email_address,
name: values.full_name,
message: values.message,
_csrf: csrfToken,
},
{ websiteId }
);
} catch (error) {
handleError(error);
actions.setSubmitting(false);
}
Postman endpoint seems to be sending the same data, after loading the /getCsrfToken endpoint and I manually update the _csrf token.
Is there something I'm not doing correctly? I think it may be to do with Node.js's cookie system.
I think your problem is likely to be related to CORS (your dev tools will probably have sent a warning?).
Here's the simplest working back-end and front-end I could make, based on the documentation:
In Back-End (NodeJS with Express) Server:
In app.js:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
const cors = require('cors');
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
var app = express()
const corsOptions = {
origin: "http://localhost:3000",
credentials: true,
}
app.use(cors(corsOptions));
app.use(cookieParser())
app.get('/form', csrfProtection, function (req, res) {
res.json({ csrfToken: req.csrfToken() })
})
app.post('/process', parseForm, csrfProtection, function (req, res) {
res.send('data is being processed')
})
module.exports = app;
(make sure you update the corsOptions origin property to whatever your localhost is in React.
In Index.js:
const app = require('./app')
app.set('port', 5000);
app.listen(app.get('port'), () => {
console.log('App running on port', app.get('port'));
});
In React:
Create file "TestCsurf.js" and populate with this code:
import React from 'react'
export default function TestCsurf() {
let domainUrl = `http://localhost:5000`
const [csrfTokenState, setCsrfTokenState] = React.useState('')
const [haveWeReceivedPostResponseState, setHaveWeReceivedPostResponseState] = React.useState("Not yet. No data has been processed.")
async function getCallToForm() {
const url = `/form`;
let fetchGetResponse = await fetch(`${domainUrl}${url}`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"xsrf-token": localStorage.getItem('xsrf-token'),
},
credentials: "include",
mode: 'cors'
})
let parsedResponse = await fetchGetResponse.json();
setCsrfTokenState(parsedResponse.csrfToken)
}
React.useEffect(() => {
getCallToForm()
}, [])
async function testCsurfClicked() {
const url = `/process`
let fetchPostResponse = await fetch(`${domainUrl}${url}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"xsrf-token": csrfTokenState,
},
credentials: "include",
mode: 'cors',
})
let parsedResponse = await fetchPostResponse.text()
setHaveWeReceivedPostResponseState(parsedResponse)
}
return (
<div>
<button onClick={testCsurfClicked}>Test Csurf Post Call</button>
<p>csrfTokenState is: {csrfTokenState}</p>
<p>Have we succesfully navigates csurf with token?: {JSON.stringify(haveWeReceivedPostResponseState)}</p>
</div>
)
}
Import this into your app.js
import CsurfTutorial from './CsurfTutorial';
function App() {
return (
<CsurfTutorial></CsurfTutorial>
);
}
export default App;
That's the simplest solution I can make based on the CSURF documentations example. It's taken me several days to figure this out. I wish they'd give us a bit more direction!
I made a tutorial video in case it's of any help to anyone: https://youtu.be/N5U7KtxvVto

Can't deploy simple node.js app to heroku nor MongoDB

So im trying to deploy a simple twitter like app to HEROKU or MongoDB and i'm currently nailing either. For mongodb I get one out of two outcomes, either a internal server error or the actual code displaying on the browser instead of the app. Since I have two separate folders for each implementation i'm going to post subsequently.
MONGODB
Index.js (This is the server side node code)
const express = require('express');
//Cors permite que cualquiera se comunique con el server.
const cors = require('cors');
const monk = require('monk');
const Filter = require('bad-words');
const rateLimit = require('express-rate-limit');
const filter = new Filter();
const app = express();
const db = monk(process.env.MONGO_URI || 'localhost/meower');
const mews = db.get('mews');
//ORDER MATTERS, WHAT IS FIRST GETS EXECUTED FIRST
app.enable('trust proxy');
app.use(cors());
//any incoming request that is JSON will pass
app.use(express.json());
//server, when you get a request run this function.
app.get('/',(request,response) => {
res.json({
message: 'Meower!'
});
});
app.get('/mews', (req,res) => {
mews
.find()
.then(mews => {
res.json(mews);
});
});
function isvalidmew(mew){
return mew.name && mew.name.toString().trim() !== '' &&
mew.content && mew.content.toString().trim() !== '';
}
//limit the submit rate
app.use(rateLimit({
windowMs: 30 * 1000,
max: 2
}));
//this will wait for incoming data and insert in database
app.post('/mews', (req,res) => {
if(isvalidmew(req.body)){
const mew = {
name: filter.clean(req.body.name.toString()),
content: filter.clean(req.body.content.toString()),
created: new Date()
};
mews
.insert(mew)
.then(createdMew => {
res.json(createdMew);
});
} else {
res.status(422);
res.json({
message:'Hey! Name and Content are required!'
});
}
});
//abre el server en el puerto 5000
app.listen(5000, () => {
console.log('Listening on http://localhost:5000');
});
Client.js
const form = document.querySelector('form');
const loadingElement = document.querySelector('.loading');
const mewsElement = document.querySelector('.mews');
const API_URL = 'http://localhost:5000/mews';
loadingElement.style.display = '';
console.log('hola')
listallmews();
form.addEventListener('submit', (event) => {
event.preventDefault();
const formData = new FormData(form);
//We grab the stuff from the form
const name = formData.get('name');
const content = formData.get('content');
//We put it in an object
const mew = {
name,
content
};
//We send the data to the server
form.style.display = 'none';
loadingElement.style.display = '';
fetch(API_URL, {
method: 'POST',
body: JSON.stringify(mew),
headers : {
'content-type':'application/json'
}
}).then(response => response.json())
.then(createdMew => {
form.reset();
setTimeout(() => {
form.style.display = '';
},30000);
listallmews();
});
});
function listallmews(){
mewsElement.innerHTML = '';
fetch(API_URL)
.then(response => response.json())
.then(mews => {
console.log(mews);
mews.reverse();
mews.forEach(mew =>{
const div = document.createElement('div');
const header = document.createElement('h3');
header.textContent= mew.name
const contents = document.createElement('p')
contents.textContent= mew.content;
const date = document.createElement('small');
date.textContent = new Date(mew.created);
div.appendChild(header);
div.appendChild(contents);
div.appendChild(date);
mewsElement.appendChild(div);
});
loadingElement.style.display = 'none'
});
}
now.json
{
"name": "camitter-api",
"version": 2,
"builds": [
{
"src": "index.js",
"use": "#now/node-server"
}
],
"routes": [
{ "src": "/.*", "dest": "index.js" }
],
"env": {
"MONGO_URI": "#camitter-db"
}
}
and package.json
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"keywords": [],
"author": "CJ R. <cj#null.computer> (https://w3cj.now.sh)",
"license": "MIT",
"dependencies": {
"bad-words": "^1.6.3",
"cors": "^2.8.4",
"express": "^4.16.3",
"express-rate-limit": "^3.1.1",
"monk": "^6.0.6",
"morgan": "^1.9.1"
},
"devDependencies": {
"nodemon": "^1.18.4"
}
}
And this is the terminal output on implementation. Currently the link shows "internal server error"
Alejandro#DESKTOP-LOJH5G7 MINGW64 ~/Desktop/Programacion/Meower
$ now secrets add camisite mongodb+srv://alenieto:myactualpassword#camisite-irtu2.mongodb.net/test?retryWrites=true&w=majority
[1] 444
Alejandro#DESKTOP-LOJH5G7 MINGW64 ~/Desktop/Programacion/Meower
$ Now CLI 18.0.0
Success! Secret camisite added under alenieto97 [709ms]
$ now -e MONGO_URI=#camisite
Now CLI 18.0.0
? Set up and deploy “~\Desktop\Programacion\Meower”? [Y/n] y
? Which scope do you want to deploy to? Alejandro Nieto
? Found project “alenieto97/meower”. Link to it? [Y/n] n
? Link to different existing project? [Y/n] n
? What’s your project’s name? camisite
? In which directory is your code located? ./
No framework detected. Default project settings:
- Build Command: `npm run now-build` or `npm run build`
- Output Directory: `public` if it exists, or `.`
� Inspect: https://zeit.co/alenieto97/camisite/ei55o9z4q [2s]
✅ Production: https://camisite.now.sh [copied to clipboard] [5s]
� Deployed to production. Run `now --prod` to overwrite later (https://zeit.ink/2F).
� To change the domain or build command, go to https://zeit.co/alenieto97/camisite/settings
[1]+ Done now secrets add camisite mongodb+srv://alenieto:lapata97#camisite-irtu2.mongodb.net/test?retryWrites=true
Alejandro#DESKTOP-LOJH5G7 MINGW64 ~/Desktop/Programacion/Meower
$ cd server
Alejandro#DESKTOP-LOJH5G7 MINGW64 ~/Desktop/Programacion/Meower/server
$ now -e MONGO_URI=#camisite
Now CLI 18.0.0
❗️ The `name` property in now.json is deprecated (https://zeit.ink/5F)
� Inspect: https://zeit.co/alenieto97/camitter/6b76zrggu [3s]
✅ Preview: https://camitter.alenieto97.now.sh [copied to clipboard] [20s]
� To deploy to production (camitter.now.sh), run `now --prod`
❗️ Zero-configuration deployments are recommended instead of a `builds` property in `now.json`. The "Build and Development Settings" in your Project will not apply.
Alejandro#DESKTOP-LOJH5G7 MINGW64 ~/Desktop/Programacion/Meower/server
HEROKU
Here i'm pretty sure im doing something wrong on the index.js or client.js or both. I saw tons of guides and have all the files necesary. When I deploy, the app simply doesn't work. Since I actually tried to adapt the code to work on Heroku I'm pretty sure the problem lies in the code itself. This is The folder:
node_modules
.gitignore
index.js
package_lock.json
client.js
favicon.ico
index.html
loading.gif
styles.css
Procfile
Index.js
const express = require('express');
//Cors permite que cualquiera se comunique con el server.
const cors = require('cors');
const Filter = require('bad-words');
const rateLimit = require('express-rate-limit');
const { Pool, Client } = require('pg');
const port = process.env.PORT;
const connectionString = 'postgres://gvvsunuvtdhxpq:e9d3239ab17ea6f38d0b6303dee62b7704b37574e5eb2783ca7edb868cc7192a#ec2-18-235-20-228.compute-1.amazonaws.com:5432/d7df9kofqifk5b'
const pool = new Pool({
connectionString: connectionString,
})
const filter = new Filter();
const app = express();
//ORDER MATTERS, WHAT IS FIRST GETS EXECUTED FIRST
app.enable('trust proxy');
app.use(cors());
//any incoming request that is JSON will pass
app.use(express.json());
//server, when you get a request run this function.
app.get('/',(request,response) => {
res.json({
message: 'Meower!'
});
});
app.get('/mews', async (req, res) => {
try {
const client = await pool.connect()
const result = await client.query('SELECT * FROM test_table');
const results = { 'results': (result) ? result.rows : null};
res.render('pages/mews', results );
client.release();
} catch (err) {
console.error(err);
res.send("Error " + err);
}
})
function isvalidmew(mew){
return mew.name && mew.name.toString().trim() !== '' &&
mew.content && mew.content.toString().trim() !== '';
}
//limit the submit rate
app.use(rateLimit({
windowMs: 30 * 1000,
max: 2
}));
//this will wait for incoming data and insert in database
app.post('/mews', (req,res) => {
if(isvalidmew(req.body)){
const mew = {
name: filter.clean(req.body.name.toString()),
content: filter.clean(req.body.content.toString()),
created: new Date()
};
mews
.insert(mew)
.then(createdMew => {
res.json(createdMew);
});
} else {
res.status(422);
res.json({
message:'Hey! Name and Content are required!'
});
}
});
app.listen(port, () => {
console.log('Listening on PORT');
});
Client.js
const form = document.querySelector('form');
const loadingElement = document.querySelector('.loading');
const mewsElement = document.querySelector('.mews');
const API_URL = 'https://camisite.herokuapp.com/mews';
loadingElement.style.display = '';
listallmews();
form.addEventListener('submit', (event) => {
event.preventDefault();
const formData = new FormData(form);
//We grab the stuff from the form
const name = formData.get('name');
const content = formData.get('content');
//We put it in an object
const mew = {
name,
content
};
//We send the data to the server
form.style.display = 'none';
loadingElement.style.display = '';
fetch(API_URL, {
method: 'POST',
body: JSON.stringify(mew),
headers : {
'content-type':'application/json'
}
}).then(response => response.json())
.then(createdMew => {
form.reset();
setTimeout(() => {
form.style.display = '';
},30000);
listallmews();
});
});
function listallmews(){
mewsElement.innerHTML = '';
fetch(API_URL)
.then(response => response.json())
.then(mews => {
console.log(mews);
mews.reverse();
mews.forEach(mew =>{
const div = document.createElement('div');
const header = document.createElement('h3');
header.textContent= mew.name
const contents = document.createElement('p')
contents.textContent= mew.content;
const date = document.createElement('small');
date.textContent = new Date(mew.created);
div.appendChild(header);
div.appendChild(contents);
div.appendChild(date);
mewsElement.appendChild(div);
});
loadingElement.style.display = 'none'
});
}
Procfile
web: node index.js
Package.json
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"keywords": [],
"author": "CJ R. <cj#null.computer> (https://w3cj.now.sh)",
"license": "MIT",
"dependencies": {
"bad-words": "^1.6.3",
"cors": "^2.8.5",
"express": "^4.16.3",
"express-rate-limit": "^3.1.1",
"monk": "^6.0.6",
"morgan": "^1.9.1",
"pg": "^7.18.2"
},
"devDependencies": {
"nodemon": "^1.18.4"
}
}
I appreciate a lot any help to deploy on any of the two platforms, im trying to make the most out of this quarantine and have been trying to solve this for twenty hours straight. Cheers to any isolated folks!
Change index.js file
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Our app is running on port ${ PORT }`);
});
You can also refer https://help.heroku.com/P1AVPANS/why-is-my-node-js-app-crashing-with-an-r10-error

Categories

Resources