How to fix err_http_headers_sent - javascript

I tried fix an error: [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client but I haven't idea how to do it. I've tried many possibilities, but they haven't worked, or I have wrong used that solutions.
server.js
const express = require('express')
const mysql = require('mysql')
const cors = require('cors')
const app = express()
const parser = express.urlencoded({extended:false})
app.use(cors())
app.set('view engine', 'ejs')
app.use(express.static('public'));
const con = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "expenseapp"
})
con.connect(err=>{
if(err)
throw err;
console.log('connected!');
})
let array = []
app.get('/',(req,res)=>{
res.render('index')
let queryName = "SELECT * from `expenses`";
con.query(queryName, (err,res)=>{
if(err)
throw err
res.forEach(element => {
array.push(element)
});
})
res.json(array)
})
app.get('/add', (req,res)=>{
res.render('add')
})
app.post('/add', parser, (req,res)=>{
let array = [req.body.product, req.body.cost]
let sqlquery = "INSERT INTO `expenses` (name, cost) VALUES (?)";
con.query(sqlquery, [array], (err,res)=>{
if(err)
throw err
console.log("saved new product");
})
res.render('add')
})
app.listen(PORT, ()=>console.log(`Server's running on PORT ${PORT}`))
app.js
.then(response => {return response.json()})
.then(data => console.log(data))
.catch(err => console.log(err))
directory order:
node_modules
public:
___javascripts
___app.js
___styles
___style.css
views:
___add.ejs
___index.ejs
package-lock.json
package.json
server.js
Give me answer how to fix that trouble please. Thanks :)

This request handler:
app.get('/',(req,res)=>{
res.render('index')
let queryName = "SELECT * from `expenses`";
con.query(queryName, (err,res)=>{
if(err)
throw err
res.forEach(element => {
array.push(element)
});
})
res.json(array)
})
is calling both res.render() and res.json(). Each of those tries to send a response to the request and the second one will trigger the error you report because you only get to send one response per request. It's not clear exactly what you want this route to be. If you want to pass the query results to the template, then you would do something like this:
app.get('/',(req,res)=>{
const queryName = "SELECT * from `expenses`";
con.query(queryName, (err,res)=>{
if (err) {
console.log(err);
res.sendStatus(500);
return;
}
res.render('index', res); // if res isn't already an array, convert it to an array
});
});
Note, several things being done differently here:
Add error handling on the query that logs the error and sends an actual error response. throw err will not be useful here.
Remove res.json() so we're only sending one response instead of two.
Call res.render() with your template and pass it the array of results so the template index can use that data in generating the page.
Move the res.render() inside the database callback where we actually have the data available.
If you intend for this route to accomplish something different than I've coded it for here, then please describe what this route is supposed to do.
FYI, you should not be using if(err) throw err; in any asynchronous callback. It's not doing you any good as none of your code can actually catch any of those asynchronously thrown exceptions and do something intelligent with them. You need real error handling in all your asynchronous operations. Don't skip that step when writing code. Don't leave it for later. Think about error handling as a primary concept when designing and first writing your code.

Related

Connect to mySql on VPS server eventhough works locally

I have a React front-end, with a Node back-end to connect to mySql for data. It works exactly how I want locally. However, now that I'm moving it to a VPS server, I can't seem to get my configuration correct.
The error I get is: create:1 Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0. It's actually returning HTML, of the page that says it's can't find the page.
I setup an express server with this code:(I do realize I need to move login details to an ENV file... just haven't yet)
const express = require('express');
const mysql = require('mysql2');
const connection = mysql.createPool({
host : 'localhost:3306',
user : 'root',
password : 'xxxxx',
database : 'ppr'
});
const app = express();
app.use(express.json());
app.use(express.urlencoded({extended: false}));
app.get('/api/clients/all', function (req, res) {
// Connecting to the database.
connection.getConnection(function (err, connection) {
// Executing the MySQL query (select all data from the 'clients' table).
connection.query("SELECT * FROM clients", function (error, results) {
// If some error occurs, we throw an error.
if (error) throw error;
console.log(results);
res.json(results);
});
});
});
// Starting our server.
app.listen(3001, () => {
console.log('Listening on port http://localhost:3001');
});
I start this running on the server, and it runs. No errors.
But then my React app makes the first api call, and I get the error because it returns HTML instead of the data I'm expecting. Do I need to do something different to make it work in production? I have proxy setup in my local machine which probably makes it work... but what do I change for production?
Here's the API call that works locally, but not on the server if it helps:
componentDidMount() {
fetch('/api/clients/all')
.then(res => res.json())
.then((result) => {
this.setState({ clients: result });
console.log(result);
})
.then(
fetch(`/api/policy/all`)
.then(res => res.json())
.then((result) => {
this.setState({ policies: result });
console.log(result);
})
);
}

How to improve node js code for production and split it properly across files?

I'm new to javascript and node.js.
Can someone answer the following questions.
1. How I split the PostgreSQL part properly in an other file.
2. How I the pest practice is to use the pg pools.
3. How I improve this code for production.
const express = require('express');
const app = express();
const pg = require('pg');
const pool = new pg.Pool({
user: 'admin',
password: 'test123!',
host: '127.0.0.1',
port: '5432',
database: 'test_db'
});
app.get('/api/recipes', function(req, res){
pool.connect(function(err, client, done) {
if(err){
console.log('Connection failed '+ err);
res.status(400).send(err);
}
client.query('SELECT * FROM recipes;', function(err, result) {
done();
if(err){
console.log('Error with query! ERROR code: ' + err.code);
res.status(400).send(err);
}
else{
res.status(200).send(result.rows)
}
});
});
});
app.get('/api/recipes/:id', function(req, res){
var id = req.params.id;
pool.connect(function(err, client, done) {
if(err){
console.log('Connection failed ' + err);
res.status(400).send(err);
}
else{
client.query('SELECT * FROM recipes WHERE recipes_id = $1;', [id], function(err, result) {
done();
if(err){
console.log('Error with query! ERROR code: ' + err.code);
res.status(400).send(err);
}
else{
res.status(200).send(result.rows)
}
});
}
});
});
app.listen(3000,function(){
console.log('Server listen on port 3000');
});
There are a lot of ways folks go to split the code you've described. I'll take it piece by piece.
First, pull any configurable variables out and setup one file that can get them from the environment (possibly with dev defaults in place, your choice on that). You can use a library like commander or convict, but honestly I prefer to just write a simple file that pulls them myself:
// ./config.js
module.exports = {
pool: {
user: process.env.DB_USER || 'admin',
password: process.env.DB_PW || 'test123!',
host: process.env.DB_HOST || '127.0.0.1',
port: process.env.DB_PORT || '5432',
database: process.env.DB_NAME || 'test_db'
}
};
As for your database calls, some folks like to use ORM-like stuff such as sequelize, but again I tend to start simple and add things as needed. In your case, you should think about what boilerplate stuff you can make common code around, and then wrap those into simple modules that only expose to the calling code stuff it really needs. For example, you will note that most of your routes are going to connect to the pool, test for an error, then run a query if it doesn't error out, and finally render either the error or query results, right? So that can all be wrapped into a fairly simple query function that handles the boilerplate internally and works with just a query expression and a callback, for example:
// ./db/index.js
const pg = require('pg');
const config = require('./config');
const pool = new pg.Pool(config.pool);
function query(sql, params, callback) {
// maybe check for valid inputs here or something, but at least normalize in case folks don't pass params
if(arguments.length < 3) {
callback = params;
params = null;
}
pool.connect((err, client, done) => {
// just exit here and let the calling code know there was a problem
if(err) return callback(err);
// I haven't tested this w/ the pg library recently, you might have to do two of these if it doesn't like null as a second argument
client.query(sql, params, (err, result) => {
if(err) return callback(err);
done();
// calling code probably doesn't care about anything but rows, but you can do other stuff here if you prefer
return callback(null, result.rows);
});
});
};
// You can also add additional functions if you want shorthand for doing things like query by ID or with params, or similar
module.exports = { query };
I also think that it can be helpful to store the SQL strings somewhere centrally, or on model objects, just to make the routing code note have to care about that. For a super simple example using your two routes, I might do something like this:
// ./db/queries.js
module.exports = {
RECIPES: {
LIST: 'SELECT * FROM recipes;',
FIND_BY_ID: 'SELECT * FROM recipes WHERE recipes_id = $1;'
}
};
Ok, so now your routing code can be quite simple, you can just get the db module and work the query, letting the routing worry just about what it's got to do with the request and response. Another option that folks like is to actually create a module for each model in your app (e.g. a Recipe) that wraps the above two files into a set of static functions so that your routes don't even know they're querying specifically. The calls in that case would be something like Recipe.list(cb) or Recipe.findById(id, cb). This is a style made popular by Ruby on Rails a few years ago, it has mixed acceptance in the Node community, but I'm mentioning it for completeness.
// ./routes/recipes.js
const router = require('express').Router();
const db = require('./db');
const queries = require('./db/queries');
router.get('/api/recipes', (req, res, next) => {
db.query(queries.RECIPES.LIST, (err, rows) => {
if(err) return next(err);
return res.send(rows); // status 200 is the default here
});
});
router.get('/api/recipes/:id', (req, res, next) => {
const id = req.params.id;
db.query(queries.RECIPES.FIND_BY_ID, [id], (err, rows) => {
if (err) return next(err);
return res.send(rows);
});
});
Finally, in your main Express setup file:
// ./app.js
const express = require('express');
const app = express();
const recipeRoutes = require('./routes/recipes') // note if you have an index.js file that gets imported just by calling for the folder, so that's a way to group features as well
app.use(recipeRoutes);
// I'm a big fan of error handling middleware. There's a more complex approach I did in [praeter][4] that gives you http-verb based errors that you can then catch and send the appropriate status, but that's again more complex than you might need here.
app.use((err, req, res, next) => {
// this can be as simple or as complex as you like.
// note it's a best practice to send only "clean" messages to the client, so you don't give away that you're using a Postgres db or other stuff that makes hacking easier.
console.error(err);
res.status(500).send('Oops! Something went wrong!!');
});
Obviously, there's a lot of ways to skin this cat, so I'd recommend mostly just looking for where you're repeating yourself, and then refactor to repeat less. Also, if you're interested in making more production-ready apps in general, the 12 factor app is a must-read.
To answer number 1,
dbPool.js
const pg = require('pg');
export.pool = new pg.Pool({
user: 'admin',
password: 'test123!',
host: '127.0.0.1',
port: '5432',
database: 'test_db'
});
app.js
const express = require('express');
const app = express();
const pool = require('./dbPool');
....
You should create config file and require that file in app.js
--config
----config.js
--app.js
var config = {
production: {
pool: {
user: 'admin',
password: 'test123!',
host: '127.0.0.1',
port: '5432',
database: 'test_db'
}
},
development: {
pool: {
user: 'admin',
password: 'test123!',
host: '127.0.0.1',
port: '5432',
database: 'test_db'
}
}
}
exports.get = function get(env) {
return config[env] || config.development;
}

SQL Server returning results twice on a single call?

I have connected a SQL Server database to a simple node.js server. When I run the code I get both recordsets and recordset returned to me. They both essentially contain the same data. I can work with this but it seems redundant and would be neater to just call exactly the records I need.
I was hoping to get an clear ELI5 explanation as mssql npm documentation is somewhat confusing in my opinion.
Here is the code below:
const express = require('express');
const cors = require('cors');
const sql = require('mssql');
const app = express();
const sqlServer = 'hasea\\SQLExpress'
const selectAllQuery = 'SELECT * FROM dbo.users';
const config = {
user: 'nbar',
password: 'nb',
server: sqlServer,
database: 'nirvanaBar'
}
// SQL Select function
function DBconn(query, res) {
sql.connect(config, function (err) {
if (err) console.log(err);
var request = new sql.Request();
request.query(query, function (err, row) {
if (err) console.log(err)
res.json({
data: row
})
})
})
}
app.use(cors());
app.get('/', (req, res) => {
res.send("Hello from the server")
});
app.get('/users', (req, res) => {
//query?
//var andrew = "select * from dbo.users where firstName = 'Andrew';"
var matt = "select * from dbo.users where firstName = 'Matt';"
//DBconn(selectAllQuery,res);
DBconn(matt, res);
})
app.listen(4000, () => {
console.log(`Server started on port 4000`)
})
The results:
I can see this has being brought up before but I am not understanding what is going on nor does the documentation provide much information as to why this would be the case. I can use the data, I just thought it would be neater to return both recordsets and recordset.
Thanks in advance
This is the expected behaviour of mssql have a look at the documentation here. When you execute multiple statements it allows you to have multiple recordsets
You will notice that there is in fact 2 properties
recordset (singular)
and
recordsets (plural)
recordset (singular) refers to the first statement that is executed. In your case you can just use this
recordsets (plural) is an array of recordsets, in your case there will only be one in the array as you are only running one statement.

How to send json from nodejs server to client js file using Express and MongoDB

I am new to Nodejs and Express and want to search some results from mongoDB and show it on client browser, i can find the values from the mongoDB query but not able to send it to client js file,
It says doc is not defined, any help will be appreciated.
***app.js(Server)***
var bodyParser = require("body-parser");
var express = require("express");
var app = express();
var port = "8001";
var mongo= require('mongodb');
var mongoClient=mongo.MongoClient;
app.use(bodyParser.json());
app.use(express.static('public'));
app.get('/home', function(req, res) {
res.sendFile(__dirname + "/public/views/index.html");
});
app.listen(port, function() {
console.log("Server running at:" + port);
})
app.post("/response", function(req, res) {
var t = req.body;
mongoClient.connect("mongodb://localhost:27017/query", function(err,db){
cursor =db.collection('response').find({"name1":t.text},{"name2":1, "_id":0});
cursor.each(function(err, doc) {
if (doc != null) {
console.log(doc);
}
});
})
res.send(doc);
});
***index.js(Client Side)***
$.ajax({
url: '/response',
type:"POST",
contentType:"application/json; charset=utf-8",
complete: function(data) {
console.log(data.responseText);
alert(data.responseText);
}
});
doc is a variable local to your closure and therefore not available when you call res.send(doc).
In addition to that, you are iterating over all of your documents. You need to choose which one to return.
I recommend something like this:
cursor = db.collection('response').find({"name1":t.text},{"name2":1, "_id":0});
cursor.each(function(err, doc) {
if (doc != null) {
console.log(doc);
return res.json(doc); // return the first document found
}
});
Also note:
you should sanitize your data before passing it into the query
you shouldn't connect to the database on each request, instead set up mongo in the application context
you should check err to see if mongo returned an error before trying to iterate the cursor
EDIT:
To be more specific, the whole block should look like this:
app.post("/response", function (req, res) {
var t = req.body;
mongoClient.connect("mongodb://localhost:27017/query", function (err, db) {
if (err) {
return res.json(err);
}
db.collection('tweets').findOne({"name1": t.text}, {"name2": 1, "_id": 0}, function (err, doc) {
if (doc != null) {
console.log(doc);
return res.json(doc);
}
return res.sendStatus(404);
});
});
});
A few things:
cursor.each() has been deprecated in favour of cursor.forEach() assuming you're running a recent version of mongo
Your first line in a callback should be something like if (err) { console.error(err) } - at this point you'd probably see that your query is invalid:
Your query should probably look like .find({'name1': t.text, 'name2': 1, '_id': 0})
If you are referencing an auto-generated mongo ObjectID as _id, you have to use '_id': new mongo.ObjectID(<whatever string holds the _id>) in order for it to work. If you didn't specify an _id on creation, the automatically generated ObjectID will require this.
The mongo docs are great, highly recommend leafing through them for examples and which bits take which arguments and the options for all of them.
Consider using promises instead of callbacks to help tidy up. It's really easy with mongo - you just don't specify a callback function, and instead tack a .then(document => { ... }) on the end, and a single .catch(err => {console.error(err)}) will catch errors at the db, collection and cursor levels.
With jQuery, consider using .done(result => {...}) and .fail(err => { ... }) (aka promises) instead of complete for your ajax calls, and whatever you do, don't forget to attach an error handler. (I'm not even sure 'complete' is the right property, might depend on which jQuery you're using)
If you're doing an AJAX POST you should probably attach some data (and a dataType)to it. Otherwise you'll still get no records because req.body will be undefined or empty.
In the case of an error, you should be responding with res.status(500); res.end() at a minimum so you can tell when something has gone wrong on the server end.
To help along, console.log(req.body) right at the top of your function so you know what data is arriving.
Finally, if you intend on responding with JSON - use res.json(doc) instead of res.send(doc)

Why isn't Node.js Express with MongoDB responding to fetch API calls (ReactJS and Redux)?

Using ReactJS, Redux, Webpack, Node.js and Express with MongoDB, I am following the tutorial https://github.com/vasansr/mern-es6 and trying to integrate it into my project. First, I am trying to make a POST request to the server I created. And it gets a response with a success and no error is logged. Yet inside the server POST API, it does not log console.log('Req body', req.body);, and in terminal I checked to see if the database has been created with mongo -> show dbs but it is empty.
Could it be that something is intercepting the request from the server? What could be the issue?
This...
app.use('/', function (req, res) {
res.sendFile(path.resolve('client/index.html'));
});
comes before:
app.post('/api/users/', function(req, res) {
//...
});
Since it's app.use the POST /api/users will still hit that middleware, and res.sendFile ends the request/response. You'll probably see that your post is getting back the client HTML.
Try moving your client HTML endpoint to the end of your middleware, just before the error handlers if you have them. That way, it'll only get used if none of your API endpoints match. Or if you want just GET / to return the HTML, change use to get:
app.use(webpackDevMiddleware(compiler, {noInfo: true, publicPath: config.output.publicPath}));
app.use(webpackHotMiddleware(compiler));
app.use(express.static('dist')); //where bundle.js is
app.use(bodyParser.json());
app.post('/api/users/', function(req, res) {
console.log('Req body', req.body);
var newUser = req.body;
db.collection('users').insertOne(newUser, function(err, result) {
if(err) console.log(err);
var newId = result.insertedId;
db.collection('users').find({_id: newId}).next(function(err, doc) {
if(err) console.log(err);
res.json(doc);
});
});
});
app.get('/', function (req, res) {
res.sendFile(path.resolve('client/index.html'));
});
app.post('/api/users/', function(req, res) {
console.log('Req body', req.body);
var newUser = req.body;
db.collection('users').insertOne(newUser, function(err, result) {
if(err) console.log(err);
var newId = result.insertedId;
db.collection('users').find({_id: newId}).next(function(err, doc) {
if(err) console.log(err);
res.json(doc);
});
});
});
I have a small comments about this code, for if(err) console.log(err); i think you should change to if(err) return console.log(err);.
For error case, i think you need return, otherwise the below part will be excuted, and there will report some error.

Categories

Resources