I've been following a tutorial online, but modifying it for my own project. Get requests to api/posts work fine, but Post requests lead to 404 and 'Error: Can't set headers after they are sent.'. I can't work out why this is.
'use strict'
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const Post = require('./models/post_schema');
const app = express();
const router = express.Router();
const port = process.env.API_PORT || 3000;
mongoose.connect('mongodb://REDACTED');
app.use(bodyParser.urlencoded({extend: true}));
app.use(bodyParser.json());
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
res.setHeader('Cache-Control', 'no-cache');
next();
});
router.get('/', function(req, res) {
res.json({ message: 'API Initlialised'});
});
router.route('/posts')
.get(function(req, res) {
Post.find(function(err, posts) {
if (err) {res.send(err)}
res.json(posts)
})
})
.post(function(req, res) {
const post = new Post();
post.title = req.body.title;
post.text = req.body.text;
post.save(function(err) {
if (err) {res.send(err)};
res.json({ message: 'Post added!'});
});
});
app.use('/api', router);
app.listen(port, function() {
console.log(`api running on port ${port}`)
})
I've gone through the express documentation, but can't find a solution. Any help would be appreciated.
This might do the trick!
router.route('/posts')
.get(function(req, res) {
Post.find(function(err, posts) {
if (err) return res.send(err);
return res.json(posts)
})
})
.post(function(req, res) {
const post = new Post();
post.title = req.body.title;
post.text = req.body.text;
post.save(function(err) {
if (err) return res.send(err);
return res.json({ message: 'Post added!'});
});
});
Your server could send 2 http response, if an error occurred on the save method, I think that's why you get Can't set headers after they are sent., try to use return statement to stop the remaining code from executing or use else clause:
post.save(function(err) {
if (err) {
return res.json({ success: false, error: err.message });
}
res.json({ message: 'Post added!'});
});
Related
I got back on a project that I didn't touch for a while and I get this error.
MongoNetworkError: failed to connect to server [cluster0-shard-00-01-ntrwp.mongodb.net:27017] on first connect [MongoNetworkError: connection 5 to cluster0-shard-00-01-ntrwp.mongodb.net:27017 closed
I checked the connection network access and allowed everyone I checked twice the mongoose.connect CREDENTIAL and I don't see why it keeps sending me this error. I also reinstall npm mongoose.
const fs = require("fs");
const path = require("path");
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const placesRoutes = require("./routes/places-routes");
const usersRoutes = require("./routes/users-routes");
const HttpError = require("./models/http-error");
const app = express();
app.use(bodyParser.json());
app.use("/uploads/images", express.static(path.join("uploads", "images")));
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE");
next();
});
app.use("/api/places", placesRoutes);
app.use("/api/users", usersRoutes);
app.use((req, res, next) => {
const error = new HttpError("Could not find this route.", 404);
throw error;
});
app.use((error, req, res, next) => {
if (req.file) {
fs.unlink(req.file.path, (err) => {
console.log(err);
});
}
if (res.headerSent) {
return next(error);
}
res.status(error.code || 500);
res.json({ message: error.message || "An unknown error occurred!" });
});
mongoose
.connect(
`mongodb+srv://XXXX:XXXX#cluster0-ntrwp.mongodb.net/XXXX?retryWrites=true&w=majority`
)
.then(() => {
app.listen(5000);
})
.catch((err) => {
console.log(err);
});
I can't figure out how to query the MySQL database from the promise in my route file. I'm writing a RESTful API to query a MySQL database with GET methods. I'm using Express and Axios for Javascript promises.
I want to get back the list of books from a SQL table and the count of how many listings in the returned JSON.
server.js
const http = require('http');
const app = require('./app');
const port = process.env.PORT || 3000;
const server = http.createServer(app);
server.listen(port);
app.js
const express = require('express');
const app = express();
const morgan = require('morgan');
const bodyParser = require('body-parser');
const mysql = require('mysql');
const bookRoutes = require('./api/routes/books');
const entryRoutes = require('./api/routes/entries');
const connection = mysql.createConnection({
host: 'localhost',
user: 'rlreader',
password: process.env.MYSQL_DB_PW,
database: 'books'
});
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'GET');
return res.status(200).json({});
}
next();
});
// Routes which should handle requests
app.use('/books', bookRoutes);
app.use('/entries', entryRoutes);
app.use((req, res, next) => { //request, response, next
const error = new Error('Not found');
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
module.exports = app;
books.js
const express = require('express');
const router = express.Router();
const axios = require('axios');
//do I import something for mysql here?
router.get('/', (req, res, next) => {
axios.get('/').then(docs => {
res.status(200).json({
"hello": "hi" //want to query MySQL database here
})
}).catch(err => {
res.status(500).json({
error: err
});
})
});
module.exports = router;
Any help would be appreciated. For starters, how do I get const connection from app.js to books.js?
I moved the code connecting to the MySQL database to a separate file and included that:
const con = require('../../db');
Next, I had to properly return the response:
router.get('/', (req, res, next) => {
let responseData = axios.get('/').then(docs => {
const sql = "SELECT title, id FROM books";
con.query(sql, function (err, result) {
if (err) {
console.log("error happened");
}
return res.status(200).json(result);
});
}).catch(err => {
res.status(500).json({
error: err
});
});
});
i'm trying to make a single page application and in the backend part i already have the code but when i want to make checks with postman of my api rest and run the server i get an error
'use strict';
require('dotenv').config();
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const routes = require('./webserver/routes');
const mysqlPool = require('./ddbb/mysql-pool');
process.on("uncaughtException", err => {
console.error("unexpected exception", err.message, err);
});
process.on("unhandledRejection", err => {
console.error("unexpected error", err.message, err);
});
const app = express();
app.use(bodyParser.json());
app.use((err, req, res, next) => {
console.error(err);
res.status(400).send({
error: `Body parser: ${err.message}`,
});
});
/**
* Enable CORS
*/
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Authorization, X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Allow-Request-Method');
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
res.header('Allow', 'GET, POST, OPTIONS, PUT, DELETE');
next();
});
app.use('/api', routes.accountRouter);
app.use('/api', routes.userRouter);
app.use((err, req, res, next) => {
const { name: errorName } = err;
if (errorName === "AccountNotActivatedError") {
return res.status(403).send({
message: err.message
});
}
return res.status(500).send({
error: err.message
});
});
async function init() {
try {
await mysqlPool.connect();
} catch(e) {
console.error(e);
process.exit(1);
}
const port = process.env.PORT;
app.listen(port, () => {
console.log(`Server running and listening on port ${port}`);
});
}
init();
in the visual studio terminal tells me that the server is listening and running on the assigned port but in the browser gives me the error 'cannot GET' and postman does not connect me
You have routes with prefix /api but not for root ('/').
Try using:
app.get('/', function (req, res, next) {
//your code here
res.send(200);
})
im trying to setup an API using node.js and in my app.js class im handling request errors where i return a 404 in case something goes wrong, now thats my problem, i can't see how am i requesting anything wrong, i am still receiving 404 error, im trying to send a post request to my API exactly like this:
{
"name":"Harry Potter 5",
"price":"12.99"
}
then i get this
Here's my app.js
const express = require('express');
const app = express();
const morgan = require('morgan');
const productRoutes = require('./api/routes/product');
const orderRoutes = require('./api/routes/order');
const bodyParser = require('body-parser');
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({
extended:false
}));
app.use(bodyParser.json());
app.use((req, res, next) => {
const error = new Error("Not found");
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
app.use('/products', productRoutes);
app.use('/orders', orderRoutes);
module.exports = app;
Here's my product.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res, next) => {
res.status(200).json({
message: 'Handling GET requests to /products'
});
});
router.post('/', (req, res, next) => {
const product = {
name: req.body.name,
price: req.body.price
};
res.status(201).json({
message: 'Handling POST requests to /products',
createdProduct: product
});
});
router.get('/:productId', (req, res, next) => {
const id = req.params.productId;
if (id === 'special') {
res.status(200).json({
message: 'You discovered the special ID',
id: id
});
} else {
res.status(200).json({
message: 'You passed an ID'
});
}
});
router.patch('/:productId', (req, res, next) => {
res.status(200).json({
message: 'Updated product!'
});
});
router.delete('/:productId', (req, res, next) => {
res.status(200).json({
message: 'Deleted product!'
});
});
module.exports = router;
It's because you are setting everything to error out :)
See the documentation from here - from the provided link:
Writing error handlers Define error-handling middleware functions in
the same way as other middleware functions, except error-handling
functions have four arguments instead of three: (err, req, res, next).
For example:
// pay attention to err param
app.use(function (err, req, res, next) {
console.error(err.stack)`
res.status(500).send('Something broke!')
})
In your code you have this bit:
app.use((req, res, next) => {
const error = new Error("Not found");
error.status = 404;
next(error);
});
which tells express that every request should be responded with a 404. You should either make it a proper error handler, or remove it.
This is because any request execute the 404 handler.
Look at this shorten version of your code:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended:false
}));
app.use(bodyParser.json());
app.use((req, res, next) => {
console.log("Got into 404 handler");
const error = new Error("Not found");
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
console.log("Got into 500 handler");
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
app.use('/products', (req, res, next) => {
console.log("Got into 200 handler");
res.status(200).end();
});
app.listen(8080);
It prints "Got into 404 handler" at each request. Now, if you comment out the 404 callback this way: all requests go through the 500 and 200 callbacks:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended:false
}));
app.use(bodyParser.json());
/* there used to be the 404 callback here */
app.use((error, req, res, next) => {
console.log("Got into 500 handler");
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
app.use('/products', (req, res, next) => {
console.log("Got into 200 handler");
res.status(200).end();
});
app.listen(8080);
Now in your specific problem, the code below would work (I just swapped the order of the handlers):
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended:false
}));
app.use(bodyParser.json());
app.use('/products', (req, res, next) => {
console.log("Got into 200 handler");
res.status(200).end();
});
app.use((req, res, next) => {
console.log("Got into 404 handler");
const error = new Error("Not found");
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
console.log("Got into 500 handler");
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
app.listen(8080);
Hope this helps.
Server side code:
var User = require("./models/user");
var express = require('express'),
app = express(),
Account = require("./models/account"),
mongoose = require('mongoose'),
passport = require("passport"),
basicAuth = require('basic-auth'),
bodyParser = require("body-parser"),
LocalStrategy = require("passport-local"),
passportLocalMongoose = require("passport-local-mongoose"); //libraries
mongoose.connect("mongodb://localhost/test");
app.set('view engine', 'ejs'); //using engine of ejs file
app.use(bodyParser.urlencoded({extended: true}));
app.use(require("express-session")({
secret: "kiss my ass",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(Account.authenticate()));
passport.serializeUser(Account.serializeUser());
passport.deserializeUser(Account.deserializeUser());
// AUTH Routes
//create account success
app.get('/success', function (req, res) {
res.render('success');
});
// deleteUser form
app.get("/delete", function(req, res, next) {
res.render("deleteuser");
});
app.get("/viewall", function(req, res, next) {
res.render("viewall");
});
//view all User form
app.get('/view', function (req, res) {
console.log('getting all user');
Account.find({})
.exec(function(err, results) {
if(err) {
res.send('error has occured');
}else{
console.log(results);
res.json(results);
}
});
});
app.get('/viewall/:id', function (req, res) {
console.log('getting one user');
Account.findOne({
_id:req.params.id
})
.exec(function(err, account) {
if(err) {
res.send('error occured');
}else{
console.log(account);
res.json(account);
}
})
})
// LOGIN for user
// render login form
app.get("/", function(req, res) {
res.render("login");
});
//login for user
//middleware
app.post("/login", passport.authenticate("local", {
successRedirect: "http://localhost:8082/viewImage.html",
failureRedirect: "http://localhost:8081/error"
}), function(req, res) {
});
//logout from basicauth
app.get('/logout', function (req, res) {
res.set('WWW-Authenticate', 'Basic realm=Authenticate Required');
return res.sendStatus(401);
// res.send("<a href='/login'>Show Users</a>");
});
//basicauth for admin login
var auth = function (req, res, next) {
function unauthorized(res) {
res.set('WWW-Authenticate', 'Basic realm=Authenticate Required');
return res.send(401);
};
var user = basicAuth(req);
if (!user || !user.name || !user.pass) {
return unauthorized(res);
};
if (user.name === 'admin' && user.pass === 'admin123') {
return next();
} else {
return unauthorized(res);
};
};
//LOGIN for admin
//render login form
app.get("/register", auth, function(req, res) {
res.render("register");
});
// register post
app.post("/register", function(req,res){
Account.register(new Account({username: req.body.username}), req.body.password, function(err, user){
if(err){
console.log(err);
return res.render('/register');
}
passport.authenticate("local")(req, res, function(){
res.redirect("/success");
});
});
});
app.listen(8081, function () {
console.log('ImageViewer listening on port 8081!');
});
JS code:
$scope.delete = function (data) {
if (confirm('Do you really want to delete?')){
$window.location.reload();
$http['delete']('/viewall/' + data._id).success(function() {
$scope.users.splice($scope.users.indexOf(data), 1);
});
}
};
html code:
<tr ng-repeat="user in users | filter:searchBox | orderBy:'+username'">
<td>{{user._id}}</td>
<td>{{user.username}}</td>
<td><button class="btn btn-primary" ng-click="delete(user)">Delete</button></td>
This is the error i got:
DELETE
XHR
http://localhost:8081/viewall/5784919136ccb93d0ba78d4b [HTTP/1.1 404 Not Found 8ms]
But when i run the url of http://localhost:8081/viewall/5784919136ccb93d0ba78d4b and it does give me the data:
{"_id":"5784919136ccb93d0ba78d4b","username":"qs","__v":0}
Anybody can help me? don't know what's with the error404 when i'm able to get the data.
You have no route for '/viewall/:id' with DELETE verb. So you should add route with DELETE verb. like
app.delete('/viewall/:id',function(req,res){
// rest of code here
// assume your model name Account
Account.remove({ _id: req.params.id },function(err,doc) {
if(err) {
return res.status(400).send({msg: 'Error occurred during delete account'});
}
return res.status(200).send({msg: 'Successfully deleted'});
});
}
and you should reload after success in your angular controller. like
$http['delete']('/viewall/' + data._id).then(function(response) {
$scope.users.splice($scope.users.indexOf(data), 1);
$window.location.reload();
});