I tried every possible solutions that I found, but none of them working. The body-parser is installed, the front-end is also correct. When I send a form, the url is
/addChess?name=123&hp=123&damage=123&skill=1&class=1
However, the req.body is undefined. My code:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
// DataBase
var mysql = require("mysql");
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "chess"
});
con.connect(function(err) {
if (err) {
console.log('connecting error');
return;
}
console.log('connecting success');
});
// view engine setup
app.set('views', path.join(__dirname, '/views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, '/public')));
// db state
app.use(function(req, res, next) {
req.con = con;
next();
});
app.get('/', function(req, res, next) {
var db = req.con;
db.query('SELECT chess.name AS name, chess.health AS health, chess.damage AS damage, skill.name AS skill, class.name AS class FROM chess, skill, class WHERE chess.class = class.classID AND chess.skillID = skill.skillID', function(err1, rows1) {
if (err1) {
console.log(err1);
}
db.query('SELECT name,skillID FROM skill',function(err2, rows2){
if (err2) {
console.log(err2);
}
db.query('SELECT name,classID FROM class',function(err3, rows3){
if (err3) {
console.log(err3);
}
res.render('index', {data: rows1, skillList: rows2, classList:rows3});
});
});
});
});
app.get('/addChess', function(req, res, next) {
var db = req.con;
var sql = {
name: req.body.name,
health: req.body.hp,
damage: req.body.damage,
skillID: req.body.skill,
class: req.body.class
};
//console.log(sql);
var qur = db.query('INSERT INTO chess SET ?', sql, function(err, rows) {
if (err) {
console.log(err);
}
res.setHeader('Content-Type', 'application/json');
console.log(qur.sql);
console.log(req.headers);
res.redirect('/');
});
});
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
module.exports = app;
These are not body params but ordinary request parameters. Use req.query.name etc instead. Check the documentation here: http://expressjs.com/en/api.html#req.query
Body parameters is what you usually pass when doing an HTTP POST request.
When you submit a form using the GET HTTP method, the form fields are sent in the querystring, which is not parsed by the body-parser module. For parsing the querystring, you can use url.parse(req.url, true).querystring.
Related
I am trying to do my first API Rest and I am following some tutorials. I am requesting all the articles in a MongoDB database.
This is the code of the main:
var express = require("express"),
app = express(),
http = require("http"),
bodyParser = require("body-parser"),
methodOverride = require("method-override"),
server = http.createServer(app),
mongoose = require('mongoose');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride());
// Import Models and controllers
var models = require('./models/article')(app, mongoose);
var articleCtrl = require('./controllers/articleController');
// Example Route
var router = express.Router();
router.get('/', function(req, res) {
res.send("Hello world!");
});
articles.route('/articles/:id')
.get(articleCtrl.findById);
articles.route('/articles')
.get(articleCtrl.findAllarticles)
.post(articleCtrl.addarticle);
app.use('/api', articles);
app.use(router);
mongoose.connect('mongodb://localhost/ustcg', { useNewUrlParser: true ,useUnifiedTopology: true}, function(err, res) {
if(err) {
console.log('ERROR: connecting to Database. ' + err);
}
app.listen(3000, function() {
console.log("Node server running on http://localhost:3000");
});
});
The code of the controller is here:
// Import article and mongoose
var mongoose = require('mongoose');
var Article = mongoose.model('Article');
//GET - Return a article with specified ID
exports.findById = function(req, res) {
Article.findById(req.params.id, function(err, Article) {
if(err) return res.send(500, err.message);
console.log('GET /article/' + req.params.id);
res.status(200).jsonp(Article);
});
};
//GET - Return all articles in the DB
exports.findAllarticles = function(req, res) {
Article.find(function(err, Article) {
if(err) res.send(500, err.message);
console.log('GET /article')
res.status(200).jsonp(Article);
});
};
//POST - Insert a new article in the DB
exports.addarticle = function(req, res) {
console.log('POST');
console.log(req.body);
var Article = new Article({
title: req.body.title,
paragraphs: req.body.paragraphs
});
Article.save(function(err, Article) {
if(err) return res.send(500, err.message);
res.status(200).jsonp(Article);
});
};
The model:
//We create the model
exports = module.exports = function(app, mongoose) {
var ArticleSchema = new mongoose.Schema({
title: { type: String },
paragraphs: { type: Array },
});
mongoose.model('Article', ArticleSchema);
};
When I tried to request the following http request it send me 404 error. I can not see any logs on the console so it is not entering the methods in order to see the exception is happening so I am stucked with this...
If someone could help me it would be nice.
what is articles variable in your main file.
I tried your code in my machine and struggled with articles variable and you have extra imports which are not required.
Try following code it works fine
var express = require("express");
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var articleCtrl = require('./sample.controller');
var router = express.Router();
router.get('/', function(req, res) {
res.send("Hello world!");
});
router.get('/articles/:id', articleCtrl.findById);
router.post('/articles', articleCtrl.addarticle);
router.get('/articles', articleCtrl.findAllarticles)
// app.use('/api', router);
app.use(router);
app.listen(3000, function() {
console.log("Node server running on http://localhost:3000");
});
if you uncomment app.use('/api', router); then you can also use routes as localhost:3000/api/articles
In my project I have a report hat is reachable with index.html
But this is private and I want to protect / limit access with my node app. for this I use
app.use('/allure', express.static(path.join(__alluredir , 'allure-report/')));
Then I use for bugging purpose
app.all('/allure/*', function(req, res, next) {
console.log("catched allure query");
next(); // allow the next route to run
});
But the index.html is still reachable with localhost:8080/allure/index.hmtl and also just with localhost:8080/allure/ without an console output. This confuse a lot. Anybody has an idea how to hinder access the index.html without logged in? (Is use passport)
my whole app.js file is:
const express = require('express');
const app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
const expressLayouts = require('express-ejs-layouts');
const mongoose = require('mongoose');
const passport = require('passport');
const flash = require('connect-flash');
const session = require('express-session');
var bodyParser = require('body-parser');
const fs = require('fs');
const path = require('path');
var favicon = require('serve-favicon')
const { allureGenerator } = require('./ops/copyalluredata');
app.set('socketio', io);
//app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ type: 'application/json' }));
app.use(bodyParser.urlencoded({
parameterLimit: 100000,
limit: '50mb',
extended: true
}));
var appDir = path.dirname(require.main.filename);
global.__basedir = appDir;
global.__alluredir = process.env.REPORT_DIR_ENV;
fs.readFile(path.join(appDir, '/config.xml'), (err, data) => {
if (err) throw err;
myConfigData = JSON.parse(data);
process.env.BROWSERSTACK_USERNAME = myConfigData.browserstackid;
process.env.BROWSERSTACK_ACCESS_KEY = myConfigData.browserstackkey;
process.env.BROWSERSTACK_DISPLAY_RESOLUTION="1600x1200";
console.log('config gelesen');
});
//Diese Funktion schreibt die benötigten Dateien in den allure Modul Ordner damit das Logo verwendet wird.
allureGenerator();
// Passport Config
require(path.join(appDir, '/config/passport'))(passport);
// DB Config
var db = '';
if (process.env.NODE_ENV == 'home') {
db = require(path.join(appDir, '/config/keys')).mongoURI;
console.log('keys');
}else{
db = require(path.join(appDir, '/config/keys_local')).mongoURI;
console.log('keys_local');
}
// Connect to MongoDB
mongoose
.connect(
db,
{ useNewUrlParser: true }
)
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
app.use('/allure', express.static(path.join(__alluredir , 'allure-report/')));
app.use(express.static(appDir));
// EJS
app.use(expressLayouts);
app.set('view engine', 'ejs');
app.set('views', path.join(appDir, '/views'));
app.use(
session({
secret: 'secret',
resave: true,
saveUninitialized: true
})
);
app.use(favicon(path.join(__dirname, 'css', 'fvicon.ico')))
app.use(passport.initialize());
app.use(passport.session());
// Connect flash
app.use(flash());
// Global variables
app.use(function(req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
next();
});
// Routes
app.use('/', require('./routes/index.js'));
app.use('/users', require('./routes/users.js'));
app.use('/cases', require('./routes/cases.js'));
app.use('/tcafe', require('./routes/tcafe.js'));
app.use('/imgtest', require('./routes/imgtest.js'));
app.use('/rapitest', require('./routes/restapitest.js'));
io.on('connection', function(socket){
console.log('a user connected');
});
app.all('/allure/*', function(req, res, next) {
console.log("catched allure query");
next(); // allow the next route to run
});
app.use((req, res, next) => {
next({
status: 404,
message: 'Not Found',
});
});
app.use((err, req, res, next) => {
if (err.status === 404) {
return res.status(400).render('404',{ layout: 'system.ejs' });
}
if (err.status === 500) {
return res.status(500).render('500');
}
next();
});
const PORT = process.env.PORT || 8080;
http.listen(PORT, console.log(`Server started on port ${PORT}`));
You can use something like this Or just use somemiddleware-
app.use('/allure', function(req,res,next){
if(<authenticate check>){ // some kind of authenticate check
return express.static(path.join(__dirname, 'allure'));
} else {
<Any error you want to show>
}
});
OR
app.use('/allure',<Auth Middlewarae> , express.static(path.join(__dirname, 'allure')));
I am trying to wrap my head around defining and using an API in Express, using Mongoose to hook up with MongoDB. So far I am saving objects just fine form input on the front end. However, I seem to be lost when it comes down to retrieving and displaying the data I've saved.
Here is some code:
db.js:
const mongoose = require('mongoose');
//mongoose setup
mongoose.connect(mongooseUrl, { useNewUrlParser: true });
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
console.log('mongoose connected to ' + mongooseUrl);
});
module.exports = db;
app.js:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
// import routers
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var apiRouter = require('./routes/api');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/api', apiRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
/routes/api.js:
var express = require('express');
var mongoose = require('mongoose');
var db = require('../config/db.js');
var Kitten = require('../models/kitten.js');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('api', {
title: 'Test API',
content: 'you\'re in the right place',
buttontext: 'send POST request'
});
});
router.post('/newKitten', function(req, res, next) {
var kitty = new Kitten({
name: req.body.name,
color: req.body.color
});
console.log("new kitty: " + kitty.name + " color: " + kitty.color );
kitty.save().then(console.log(kitty + " was saved to the database"));
res.send('new: ' + kitty);
});
router.get('/kittens', function (req, res, next) {
var kittens = Kitten.find({}, 'name color');
res.render('kittens', {title: 'Kittens', list_kittens: kittens });
});
module.exports = router;
models/kitten.js
const mongoose = require('mongoose');
var Schema = mongoose.Schema;
var kittenSchema = new Schema({
name: String,
color: String
});
var Kitten = mongoose.model("Kitten", kittenSchema);
module.exports = Kitten;
views/kitten.hbs:
<h1>{{title}}</h1>
<ul>
{{#each list_kittens as |kitten|}}
<li>name: {{kitten.name}}, color: {{kitten.color}}</li>
{{/each}}
</ul>
Now with all that laid out, when I visit http://localhost:3000/api/kittens this is what I see:
The kittens are stored in MongoDB, proof:
I have no idea why this is not rendering the kittens I have saved in my MongoDB database... The data is there, but I seem to be confused about how mongoose is supposed to be querying the data. Any and all help is appreciated. I've been stuck on this for a few days.
Model.find returns a promise. You have to add a function then to get the kittens and render them:
Kitten.find(...)
.then(kittens => {
res.render(...)
})
EDIT
Based on #Francisco Mateo comment, Kitten.find returns a Query you can execute with exec. Here is the code:
Kitten.find(...).exec()
.then(kittens => {
res.render(...)
})
In routes/api.js
var express = require('express');
var mongoose = require('mongoose');
var db = require('../config/db.js');
var Kitten = require('../models/kitten.js');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('api', {
title: 'Test API',
content: 'you\'re in the right place',
buttontext: 'send POST request'
});
});
router.post('/newKitten', function(req, res, next) {
var kitty = new Kitten({
name: req.body.name,
color: req.body.color
});
console.log("new kitty: " + kitty.name + " color: " + kitty.color );
kitty.save().then(console.log(kitty + " was saved to the database"));
res.send('new: ' + kitty);
});
router.get('/kittens', async function (req, res, next) { **//Change here**
var kittens = await Kitten.find({}, 'name color'); **//change here**
res.render('kittens', {title: 'Kittens', list_kittens: kittens });
});
module.exports = router;
The Kitten.find({}, 'name color') is returning a promise , so you have to wait until the data is returned.
I'm trying to make a catch-all of sorts to return data to my Author endpoint. If the url that is passed to the endpoint contains no query parameters, I want the router to return the full list of authors available. If the url contains firstName and lastName parameters, I want the controller to find the authors that match and, pass that data back to the router.
Currently if I send the urls http://localhost:3001/authors or http://localhost:3001/authors?firstName=tom&lastName=dooly, I get an error Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.
Can anyone tell me why this is happening and how to fix it?
main:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var app = express();
var dev_db_url = 'mongodb://localhost:27017/'
var mongoDB = process.env.MONGODB_URI || dev_db_url;
mongoose.connect(dev_db_url);
mongoose.Promise = global.Promise;
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
var index = require('./routes/index');
var users = require('./routes/users');
var feedEntries = require('./routes/feedEntries');
var authors = require('./routes/authors');
app.use('/', index);
app.use('/users', users);
app.use('/feedEntries', feedEntries);
app.use('/authors', authors);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not not Found');
err.status = 404;
next(err);
});
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
route:
var express = require('express');
var router = express.Router();
var authorController = require('../controllers/authorController');
authorController.findAuthorsByFirstAndLastName);
router.get('/', function (req, res) {
if(req.query.firstName||req.query.lastName) {
res.send(authorController.findAuthorsByFirstAndLastName(req,res));
}else{
res.send(authorController.author_list(req,res));
}
});
module.exports = router;
controller:
var Author = require('../models/author')
var async = require('async')
exports.author_list = function(req, res, next) {
Author.find({},function(err, authors) {
if (err){
res.send(err);
}
return.json(authors);
});
};
exports.findAuthorsByFirstAndLastName = function (req, res, next){
var query = {}
if(req.query.firstName||req.query.lastName) {
query = {$or:[{firstName:{$regex: req.query.firstName, $options: 'i'}},
{lastName:{$regex: req.query.lastName, $options: 'i'}}]}
}
else {
return res.status(500).send({ error: 'Unable to parse data'});
}
var firstName = req.body.firstName;
var lastName = req.body.lastName;
Author.find(query , function (err, authors) {
if(err) {
res.send(err);
}
res.json(authors);
});
};
You get cannot set headers after they are sent when you have two res.[whatever]s in your route. So you have res.send(functionCallThatAlsoDoesRes.Send). That's what's causing the error.
If you want a route to take multiple actions between the request and the response, you can write those as separate middlewares. Middlewares always take the arguments req, res, and next (a function that says to go to the next middleware in the list).
So, you might write:
authorController.findAuthorsByFirstAndLastName = function(req, res, next) {
if (!(req.query.firstName || req.query.lastName)) {
res.locals.getFullAuthorList = true
return next()
} else {
const query = /* whatever */
Author.find(query, (err, authors) => {
if (err) return next(err)
res.locals.authors = authors
next()
})
}
}
authorController.author_list = function(req, res, next) {
if (!res.locals.getFullAuthorList) return next() // if we already have authors we don't need to do anything
Author.find({}, (err, authors) => {
if (err) return next(err)
res.locals.authors = authors
next()
})
}
Then in your route, you'd say:
router.get('/', authorController.findAuthorsByFirstAndLastName, authorController.author_list, (req, res) => {
res.json({ authors: res.locals.authors })
})
If you haven't seen res.locals before, it's just a property on the response object that is available for you to attach things to. It persists throughout the request/response cycle and is cleared for each new request.
I made my service with express and webpack and it worked well at the beginning. The weird thing is that after a while the service(server) will hang. As the screenshot displays, no message code received.(server message screenshot)
And this happens again and again.
My app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var users = require('./routes/users');
var app = express();
var mysql = require('mysql');
var generals = require('./routes/generals');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use('/generals', generals);
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
The here is the route file: generals.js
var express = require('express');
var bodyParser = require('body-parser');
var router = express.Router();
var pool = require('./connections');
router.get('/dropDownValue/', function(req, res, next) {
pool.getConnection(function(err, connection) {
connection.query("select * from drop_down_value order by id desc", function(err, rows) {
if (!err && rows.length > 0) {
res.json(rows);
} else {
res.json([]);
}
});
});
});
And the connections file:
var mysql = require('mysql');
var pool = mysql.createPool({
host: 'xxx',
user: 'xxx',
password: 'xxx',
database: 'xxx'
});
exports.getConnection = function (callback) {
pool.getConnection(callback);
};
When you use pool.getConnection(), once you're done with the connection (i.e. the query has finished), you need to release the connection back to the pool again:
pool.getConnection(function(err, connection) {
connection.query("select * from drop_down_value order by id desc", function(err, rows) {
connection.release(); // <- this
if (!err && rows.length > 0) {
res.json(rows);
} else {
res.json([]);
}
});
});
Otherwise, once you have performed 10 queries, there are no more connections available in the pool and it will start waiting (indefinitely) for connections to be released, hanging the requests.