404 on API call in Thinkster MEAN Stack Tutorial - express

I'm following this Thinkster tutorial on building a reddit-esque web app using MEAN.
The tutorial instructs using curl to create a new post.
C:\root>curl --data "title=test&link=http://test.com" http://localhost:3000/posts
However, I get this error in response:
<h1>Not Found</h1>
<h2>404</h2>
<pre>Error: Not Found
at C:\root\app.js:30:13
at Layer.handle [as handle_request] (C:\root\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\root\node_modules\express\lib\router\index.js:312:13)
at C:\root\node_modules\express\lib\router\index.js:280:7
at Function.process_params (C:\root\node_modules\express\lib\router\index.js:330:12)
at next (C:\root\node_modules\express\lib\router\index.js:271:10)
at C:\root\node_modules\express\lib\router\index.js:618:15
at next (C:\root\node_modules\express\lib\router\index.js:256:14)
at Function.handle (C:\root\node_modules\express\lib\router\index.js:176:3)
at router (C:\root\node_modules\express\lib\router\index.js:46:12)</pre>
I looked through those files, but all the references were just showing me what happens to the error...
Here's some code
/routes/index.js:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
var mongoose = require('mongoose');
var Post = mongoose.model('Post');
var Comment = mongoose.model('Comment');
router.get('/posts', function(req, res, next){
Post.find(function(err,posts){
if(err){ return next(err); }
res.json(posts);
})
})
router.post('/posts', function(req,res,next){
var post = new Post(req.body);
post.save(function(err, post){
if(err){ return next(err); }
res.json(post);
})
})
/models/Posts.js:
var mongoose = require('mongoose');
var PostSchema = new mongoose.Schema({
title: String,
link: String,
upvotes: {type: Number, default: 0},
comments: [{type: mongoose.Schema.Types.ObjectId, ref: 'Comment'}]
});
mongoose.model('Post', PostSchema);
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();
// 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')));
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;
var mongoose = require('mongoose');
require('./models/Posts');
require('./models/Comments');
mongoose.connect('mongod:localhost/news');
I feel like I did everything correct, except I wasn't sure where to place the additional routes in the routes index file, and similarly in app.js. But this seems negligible to me. I performed all the debugging I could think of but am stuck.
It should also be noted that this tutorial was perhaps not intended for use on a Windows machine. I had to install curl and do a few other things that perhaps wouldn't be necessary on a Linux or Mac. I am using Windows 10.

Your module.exports is called prematurely in routes/index.js. Move module.exports = router; to the bottom of your file, recycle your service, and try again.
Also there are issues with app.js. See below:
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');
// Notice the differences starting here
var app = express();
var mongoose = require('mongoose');
// connect MongoDB
mongoose.connect('mongodb://localhost/news', function(err,db){
if (!err){
console.log('Connected to /news!');
} else{
console.dir(err); //failed to connect
}
});
require('./models/Posts');
require('./models/Comments');
var index = require('./routes/index');
var users = require('./routes/users');
// 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')));
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;
routes/index.js:
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Post = mongoose.model('Post');
var Comment = mongoose.model('Comment');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.get('/posts', function(req, res, next){
Post.find(function(err,posts){
if(err){
alert(err);
return next(err);
}
res.json(posts);
})
})
router.post('/posts', function(req,res,next){
var post = new Post(req.body);
post.save(function(err, post){
if(err){
alert(err);
return next(err);
}
res.json(post);
})
})
module.exports = router;

Related

express routes not working - returning 404 error

I'm trying to set up a simple express project, and backend will be purely for api and frontend will be vue. I tried adding an api router, and not only does it not work, but even the root page doesn't work. I've not coded in express for a very long time, and wondering if some one could guide me on what's the problem? The error message is 404 NotFoundError: Not Found.
I'm navigating to localhost:3000, and I can see the call on the terminal, so port should be correct too?
/src/api/urls.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.send('Just a test');
});
module.exports = router;
I didn't change the folder structure/naming for the original routes/index.js.
/src/routes/index.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.send('Just a test');
});
module.exports = router;
And for the main file
/src/app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var apiRouter = require('./api/urls');
var app = express();
app.use(require('connect-history-api-fallback')());
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
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('/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;
All good except endpoint url that should be with middleware function only. Modifying these should work,
/src/api/urls.js
var express = require('express');
var router = express.Router();
router.get('/api/test', function(req, res) {
res.send('Just a test');
});
module.exports = router;
/src/routes/index.js
var express = require('express');
var router = express.Router();
router.get('/api/test2', function(req, res) {
res.send('Just a test');
});
module.exports = router;
In app.js you should register your routes as,
// Routes
app.use([
require('./src/api/urls'),
require('./src/routes/index'),
]);
Access by url ( http://<yourhost>/api/test1 )

Pug iteration: Cannot read property 'length' of undefined

I am having the following data in js file:
let data =[
{id:1,type:"action"},
{id:2,type:"comedy"}
];
and trying to print it using pug template
doctype html
html
head
title= title
link(rel='stylesheet', href='stylesheets/style.css')
body
table
tr
th Id
th Type
each post in data
tr
td #{post.id}
td #{post.type}
block content
I get the error as "Cannot read property 'length' of undefined" at the each post line
app.js:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
let data =[
{id:1,type:"action"},
{id:2,type:"comedy"}
];
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
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);
// 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;
index.js:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Movies' });
});
module.exports = router;
Try this:
index.js:
let data =[
{id:1,type:"action"},
{id:2,type:"comedy"}
];
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Movies', data }); // you forgot passing the data array
})
Another solution is:
In the app.js, you could do this:
var app = express();
let data =[
{id:1,type:"action"},
{id:2,type:"comedy"}
];
app.locals.data = data; //added
Now you can access local variables in templates rendered within the application which mean you don't need to pass this data in the render() method

socket.io messages not appearing

I am trying to learn to use Socket.io with Express. No error messages appeared but strangely it's not working. The servermessage is not appearing and clicking the send button doesn't do anything. Any ideas?
app.js
var express = require('express');
var http = require('http');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// 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')));
app.use('/', routes);
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 handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
var server = http.createServer(app).listen(app.get('port'),
function(){
console.log("Express server listening on port " + app.
get('port'));
});
require('./routes/sockets.js').initialize(server);
module.exports = app;
routes/sockets.js
var io = require('socket.io');
exports.initialize = function(server) {
io = io.listen(server);
io.sockets.on("connection", function(socket){
socket.send(JSON.stringify(
{type:'serverMessage',
message: 'Welcome to the most interesting chat room on earth!'}));
socket.on('message', function(message){
message= JSON.parse(message);
if(message.type == "userMessage"){
socket.broadcast.send(JSON.stringify(message));
message.type = "myMessage";
socket.send(JSON.stringify(message));
}
});
});
};
public/javascripts/chat.js
var socket = io.connect('/');
socket.on('message', function (data) {
data = JSON.parse(data);
$('#messages').append('<div class="'+data.type+'">' + data.message +
'</div>');
});
$(function(){
$('#send').click(function(){
var data = {
message: $('#message').val(),
type:'userMessage'
};
socket.send(JSON.stringify(data));
$('#message').val('');
});
});
views/index.jade
extends layout
block append head
script(type='text/javascript', src='/socket.io/socket.io.js')
script(type='text/javascript', src='/javascripts/chat.js')
block content
section#chatroom
div#messages
input#message(type='text', placeholder='Enter your message here')
input#send(type='button', value='Send')
views/layout.jade
doctype html
html
block head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
header#banner
h1 Awesome Chat
block content
footer Hope you enjoy your stay here
script(type='text/javascript', src='/javascripts/jquery-1.12.4.min.js')

Running Ghost module for node.js on Heroku as subdirectory

I'm trying to install Ghost to my node app. I followed the configuration instructions and got it running with, however when I navigate to the blog subdirectory it just shows my site's homepage. I'm passing it the express app instance to start the server. What am I doing wrong?
var ghost = require('ghost');
ghost().then(function (ghostServer) {
app.use(ghostServer.config.paths.subdir, ghostServer.rootApp);
ghostServer.start(app);
});
I read online about running Ghost with ngynx or apache and configuring it to do some kind of proxy thing, but I don't really understand what all that's about.
Here is a working version of app.js for express and ghost subdirectory setup. Notice how your express routes need to be wrapped in the ghost.then() callback.
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 ghost = require('ghost');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
ghost().then(function (ghostServer) {
app.use(ghostServer.config.paths.subdir, ghostServer.rootApp);
ghostServer.start(app);
// 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')));
app.use('/', routes);
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 handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
});
module.exports = app;
const ghost = require('ghost')
const express = require('express')
const path = require('path')
const { getSubDir } = require('./node_modules/ghost/core/server/services/url/utils')
const app = express()
ghost().then((ghostServer) => {
app.use('/games', express.static(path.join(__dirname, 'games')))
app.use(getSubdir(), ghostServer.rootApp)
ghostServer.start(app)
})
latest howto included here:
https://docs.ghost.org/docs/using-ghost-as-an-npm-module

stormpath error If you do not specify a \'requestAuthenticator\' field, y

I'm getting the error specified above when trying to build a express-stormpath app. I'll list the applicable code:
Error: If you do not specify a 'requestAuthenticator' field, you must specify an ApiKey.
at Object.getAuthenticator (d:\dev\git-repos\bps\VolumeGridDataEntry\node_modules\express- stormpath\node_modules\stormpath\lib\authc\index.js:24:11)
at new RequestExecutor (d:\dev\git-repos\bps\VolumeGridDataEntry\node_modules\express-stormpath\node_modules\stormpath\lib\ds\RequestExecutor.js:37:37)
at new DataStore (d:\dev\git-repos\bps\VolumeGridDataEntry\node_modules\express-stormpath\node_modules\stormpath\lib\ds\DataStore.js:46:52)
at new Client (d:\dev\git-repos\bps\VolumeGridDataEntry\node_modules\express-stormpath\node_modules\stormpath\lib\Client.js:8:21)
at d:\dev\git-repos\bps\VolumeGridDataEntry\node_modules\express-stormpath\lib\stormpath.js:60:36
at d:\dev\git-repos\bps\VolumeGridDataEntry\node_modules\express-stormpath\node_modules\stormpath\lib\authc\ApiKeyLoader.js:14:14
at d:\dev\git-repos\bps\VolumeGridDataEntry\node_modules\express-stormpath\node_modules\stormpath\node_modules\properties-parser\index.js:348:20
at fs.js:208:20
at Object.oncomplete (fs.js:108:15)
[Updated] server.js
var express = require('express'),
session = require('express-session'),
crypto = require('crypto'),
formidable = require('formidable'),
path = require('path'),
favicon = require('serve-favicon'),
logger = require('morgan'),
cookieParser = require('cookie-parser'),
bodyParser = require('body-parser'),
index = require('./routes/index'),
users = require('./routes/users'),
stormpath = require('express-stormpath'),
config = require('./config/credentials.js'),
app = express();
function hashPwd(pwd) {
return crypto.createHash('sha256').update(pwd).digest('base64').toString();
}
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(stormpath.init(app, {
apiKeyFile: config.stormpathapi.apiKeyFile,
application: config.stormpathapi.application,
secretKey: config.stormpathapi.secretKey,
sessionDuration: 1000 * 60 * 30
}));
// domains for better error handling
app.use(function(req, res, next){
// create a domain for this request
var domain = require('domain').create();
// handle errors on this domain
domain.on('error', function(err){
console.error('DOMAIN ERROR CAUGHT\n', err.stack);
try {
// failsafe shutdown in 5 seconds
setTimeout(function(){
console.error('Failsafe shutdown.');
process.exit(1);
}, 5000);
// stop taking new requests
server.close();
try {
// attempt to use Express error route
next(err);
} catch(error){
// if Express error route failed, try
// plain Node response
console.error('Express error mechanism failed.\n', error.stack);
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Server error.');
}
} catch(error){
console.error('Unable to send 500 response.\n', error.stack);
}
});
// add the request and response objects to the domain
domain.add(req);
domain.add(res);
// execute the rest of the request chain in the domain
domain.run(next);
});
// cross-site request forgery protection
app.use(require('csurf')());
app.use(function(req, res, next){
res.locals._csrfToken = req.csrfToken();
next();
});
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'client')));
//name: cookie_name,
//store: sessionStore, // connect-mongo session store
app.use(session({
secret: config.cookieSecret,
resave: false,
saveUninitialized: true
}));
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 handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
route index.js
var express = require('express'),
stormpath = require('express-stormpath'),
router = express.Router();
router.get('/', stormpath.groupsRequired(['dataentry']), function(req, res) {
res.render('index', { title: 'Volume Grid Data Entry' });
});
module.exports = router;
Initially the route signature was this but that didn't work either. I will need the ability in the future to base page security on groups...so, I'm not sure if I should use loginRequired or groupsRequired or both :-/
router.get('/', stormpath.loginRequired, function(req, res) {
Thanks!
That code looks correct -- but where is your app.use(require('./index')); code? That will be necessary after the app.use(stormpath.init(...)) stuff above =)
NOTE: I'm the author of the express-stormpath library.
EDIT: Here's a full example:
var express = require('express'),
stormpath = require('express-stormpath'),
router = express.Router();
var app = express();
router.get('/', stormpath.groupsRequired(['dataentry']), function(req, res) {
res.render('index', { title: 'Volume Grid Data Entry' });
});
app.use('/', router);
app.listen(3000);