When I run the application in terminal (macOS) (DEGUG=app:* npm run devstart), it works fine (server Listening on port 3000 +0ms). However, when I open localhost at browser it simply appears the "Welcome Express" page, and when I go to a specific route, it appears NotFoundError: Not Found.
I have been guided by this structure (on https://expressjs.com/en/starter/faq.html).
app.use(function (req, res, next) {
res.status(404).send("Sorry can't find that!")
})
This is part of my code on one of my Controllers, where I use 404 responses:
var CCSelectionCriterion = require('../models/ccselectioncriterion');
var async = require('async');
const { body, validationResult } = require('express-validator/check');
const { sanitizeBody } = require('express-validator/filter');
// Display detail page for a specific CCSelectionCriterion.
exports.ccselectioncriterion_detail = function (req, res, next) {
CCSelectionCriterion.findById(req.params.id)
.exec(function (err, ccselectioncriterion) {
if (err) { return next(err); }
if (ccselectioncriterion==null) { // No results.
var err = new Error('CC Selection Criterion not found');
err.status = 404;
return next(err);
}
// Successful, so render.
res.render('ccselectioncriterion_detail', {title: 'CC Selection Criterion Detail', ccselectioncriterion: ccselectioncriterion});
})
};
Thank you very much.
Related
I want to create a function that return a http.Server and
Serve the text of the file testText.txt in the body of the HTTP response
when a GET request is made to the '/' route.
Parse the request for a "paragraphs" parameter.
That parameter must be an integer and represent the number of
paragraph you want to receive starting from the beginning of the test text.
Return the appropriate content in the body of the response.
If any error happens, return a 500 error.
If the provided route is not known, return a 404 error.
here is what i have so far
function makeServer() {
return http.createServer(function(req, res){
if(req.url === '/'){
fs.readFile('testText.txt', function(err , para){
console.log("Data", para);
res.end();
});
console.log("The end");
}
}
I would expect to do something like this,
var express = require('express');
var app = express();
//Handle 404 here
app.use(function (req, res, next) {
res.status(404).send({
message: "Page Not Found"
})
});
Inject the GET request to your default route
app.get('/', (req, res) => {
// **modify your existing code here**
fs.readFile('testText.txt', (e, para) => {
if (e) {
res.status(500).send({
message: "Something went wrong"
})
}
res.send(para);
});
});
app.listen(5555);
As you have mentioned in your question use that err object inside the function such as below:
function makeServer() {
return http.createServer(function(req, res){
if(req.url === '/'){
fs.readFile('testText.txt', function(err , para){
if (err) {
res.status(500).send({
message: "Something went wrong"
})
// error handling
} else {
console.log("Data", para);
res.end();
}
});
console.log("The end");
}
}
Firstly, Welcome to the node world...
1) Work with file in res
Please refer this answer. It will help you.
2) Error code 500 if any error
res.status(500).json({success: 0, error 'Something went wrong'});
3) For handle 404 if route not matched
var createError = require('http-errors');
//Install via this command-> npm i http-errors --save
app.use(function (req, res, next) {
next(createError(404));
});
Updated Post: Scroll to bottom of post for updated info
Original Post
I need some help on this one. I'm creating a route that takes FormData, validates the file data via Multer (images in this case), then validates the string data using Express-Validator. I've created a working route that completes both validations, but I can't figure out how to take any errors from Multer and return them to the client.
I have set Multer before Express-Validator, so that the req.body can be read by Express-Validator. With that, I can't figure out how to (or if I'm able at all) to pass in the Multer errors for sending back in the response.
My example below should include everything needed for examination, but if you need additional information, please let me know.
const multer = require('multer')
const {
check,
validationResult
} = require('express-validator/check');
const {
sanitizeBody
} = require('express-validator/filter');
const imageUpload = multer({
dest: 'uploads/',
limits: {
fileSize: 1000000
},
fileFilter: function (req, file, cb) {
let filetypes = /jpeg|jpg/;
let mimetype = filetypes.test(file.mimetype);
let extname = filetypes.test(path.extname(file.originalname).toLowerCase());
if (mimetype && extname) {
return cb(null, true);
}
cb(new Error('Invalid IMAGE Type'))
}
}).fields([{
name: 'cover_image',
maxCount: 1
},
{
name: 'more_images',
maxCount: 2
}
])
const validationChecks = [
check('street', 'Invalid Street Name').matches(/^[a-z0-9 ]+$/i).isLength({
min: 1,
max: 25
}).trim().escape(),
check('city', 'Invalid City Name').matches(/^[a-z ]+$/i).isLength({
min: 1,
max: 15
}).trim().escape()
]
router.post('/addnewproperty', imageUpload, validationChecks,(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log('text validation FAILED');
return res.status(400).json({
errors: errors.array()
});
}
console.log('validation PASSED');
})
Update 2/6/19
Okay, I think I have found a solution, although not what I expected.
By using the next() function within express, I'm able to utilize Multer in the first route handler where I can receive and send back Multer errors in the response. If no errors arise in this first route handler, I can call next(), to then move along to the next route handler for utilizing express-validator where I can check for and send any errors that arise from string validation.
The code below is a working example of what I'm describing. Not sure if this is acceptable code, but it is working upon some light testing. Any opinions or recommendations on this are welcome in the comments below.
// Here's the meat of what I changed.
// The config and variables set in the previous code are the same.
router.post('/addnewproperty',(req, res, next) => {
imageUpload(req,res,(err)=>{
if(err){
console.log(err.message);
return res.status(400).json(err.message)
}
next()
})
})
router.post('/addnewproperty',validationChecks,(req,res)=>{
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
errors: errors.array()
});
}
return res.sendStatus(200)
})
I'll leave this question open in case someone has a better solution of obtaining what I originally set out to do besides the code above.
I have been using a function that creates a Multer middleware that can be placed anywhere in the middleware chain. After it, you can use req.body without the other binary fields.
import { Router } from 'express';
import multer from 'multer';
function makeMulterUploadMiddleware(multerUploadFunction) {
return (req, res, next) =>
multerUploadFunction(req, res, err => {
// handle Multer error
if (err && err.name && err.name === 'MulterError') {
return res.status(500).send({
error: err.name,
message: `File upload error: ${err.message}`,
});
}
// handle other errors
if (err) {
return res.status(500).send({
error: 'FILE UPLOAD ERROR',
message: `Something wrong ocurred when trying to upload the file`,
});
}
next();
});
}
const upload = multer({ dest: 'uploads/' });
const multerUploadMiddleware = makeMulterUploadMiddleware(upload.single('image'));
const someRouter = Router();
someRouter.post('', multerUploadMiddleware, (req, res) => {
// now body contains all the fields except the one with the file
res.send(req.body);
});
export { someRouter };
I'm handling the req.body with the #hapi/joi npm package, but this should work with other validators.
note: The reason I'm not using err instanceof multer.MulterError to check if its a Multer error as described in the Multer docs (https://github.com/expressjs/multer) is because of some typescript type-checking errors.
You can get the error by calling the imageUpload middleware directly instead of using it in a middleware chain like in your code.
Non-tested snippet, but hopefully will at least nudge you in the right direction:
router.post('/addnewproperty', validationChecks, (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log('text validation FAILED');
return res.status(400).json({
errors: errors.array()
});
}
imageUpload(req, res, (multerErr) => {
if(multerErr){
console.log('Multer validation FAILED');
return res.status(400).json({
errors: [multerErr.message]
});
}else{
console.log('validation PASSED');
}
});
})
For more on the subject, here are the official Multer docs on Error handling.
Hey i will leave you with some snippets which worked for me ,
Multer without using file
const express = require('express');
const multer = require('multer');
const router = express.Router();
const { check, validationResult } = require('express-validator');
var upload = multer();
var tagCreateValidator = [
check('name', 'Name is required')
.not()
.isEmpty()
];
// #route POST api/tags
// #desc Create Tag
// #access Public
router.post('/', upload.any(), tagCreateValidator, (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
res.send(req.body);
});
this one is with file although i am not using express validator
right now, i will update this answer once this is done
const express = require('express');
const Multer = require('multer');
const gcsMiddlewares = require('../../gcs_middleware');
const router = express.Router();
const multer = Multer({
storage: Multer.storage,
limits: {
fileSize: 10 * 1024 * 1024 //Maximum file size is 10MB
}
});
// #route POST api/users
// #desc Register user
// #access Public
router.post(
'/',
multer.single('avatar'),
gcsMiddlewares.sendUploadToGCS,
(req, res, next) => {
var imageUrl;
if (req.file && req.file.gcsUrl) {
imageUrl = req.file.gcsUrl;
}
var responseBody = {
file: imageUrl,
body: req.body
};
res.send(req);
}
);
module.exports = router;
I ran into this problem today except I am not using a router. I wanted to be able to return a JSON response of the error when the fileType validation failed. I thought I would share my solution as it may help somebody else. My solution was to add a fourth parameter to the app.post() function call like so:
app.post("/post", fileUpload.single('file'), function(req, res) {
//do some stuff after a successful upload.
},
function(err, req, res, next) {
//File upload encountered an error as returned by multer
res.status(400).json({error: err.message});
})
I am constantly throwing the below error:
Error handling invalid query params:
Error: expected 422 "Unprocessable Entity", got 200 "OK"
below is my full /app.js.
'use strict'
var path = require('path');
var meal = require('./meals.js');
var express = require('express');
var router = express.Router();
var app = express();
module.exports = function(app) {
app.get('/allMeals', meal.getAllMeals, END);
app.get('/meals/:id', meal.getMealinfo, END, function(req, res, next) {
meal.findById(req.params.id).exec()
.then(function(xxx) {
if (meal == null) return next(); // Not found
return res.send('Found meal '+request.params.id);
})
.then(null, function(err) {
return next(err);
});
});
app.get('/meals/:id/options',meal.getHealthymeals, END);
function END(req,res){
res.end();
}
res.status(404).send({
message: 'Router not found.'
});
});
};
How could I better handle my invalid query params with node.js /express, to perhaps stop throwing this error?
I have installed express-validation - and would prefer this route to solving for the error; but I am unsure how to implement from the examples given.
function invalidParamHandler(req, res, next, context) {
const { error, oldQuery, nextQuery, droppedParams } = context;
// Do
}
app.use(queryValidator(invalidParamHandler));
});
Hi am a beginner to Nodejs i have used passportjs token based authentication if the user logins it provides a token for each user i want to perform some operations based for the users who has token values for example if the user want to see the list of registered users they can view it if he has the token value. Now it provides me the token value perfectly in Postman but i don't know how to store it in a variable and call it via FRONT-END. I want do it via Front End(If he clicks the get users button) it should display the list of users.I have done that in POSTMAN it works finely i don't have an idea how to do it via frontend.
My user Code(Login/Logout)
var express = require('express');
var router = express.Router();
var User = require('../models/user');
var passport = require('passport');
var Verify = require('./verify');
/* GET users listing. */
router.route('/')
.get(Verify.verifyOrdinaryUser, function(req, res, next) {
User.find({}, function (err, users) {
if (err) throw err;
res.json(users);
});
});
router.post('/register', function(req, res, next) {
User.register(new User({ username : req.body.username }),req.body.password, function(err, user) {
if (err) {
return res.status(500).json({err: err});
}
user.save(function(err,user) {
passport.authenticate('local')(req, res, function () {
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
});
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Could not log in user'
});
}
var token = Verify.getToken(user);
res.status(200).json({
status: 'Login successful!',
success: true,
token: token
});
});
})(req,res,next);
});
router.get('/logout', function(req, res) {
req.logout();
res.status(200).json({
status: 'Bye!'
});
});
module.exports = router;
Main.js File. In this main.js file i want to send that token in this get method any idea?
$(".get-users-button").click(function() {
$.ajax({
method: "GET",
url: " http://localhost:3000/users"
})
.done(function(msg) {
console.log(msg);
template(msg);
});
});
When you get back a successful response from the POST to your /login endpoint, store the token on client-side (e.g., window.localStorage.setItem('<your-namespace>-user-token', <the token goes here>);)
Then, when user clicks the 'get-users-button', get the token out of storage (e.g., window.localStorage.getItem('<your-namespace>-user-token'); and store it in a variable if you want.
Then, on your request to get users, add your { 'x-access-token': <token variable goes here> } to your request headers.
As per the documentation for Passport:
If authentication succeeds, the next handler will be invoked and the req.user property will be set to the authenticated user.
Now if I'm understanding your question correctly, you want to pass the token value you obtain from:
var token = Verify.getToken(user)
to the view in which your front-end can do something with. You can pass variables to the view using the following middleware:
app.use((req, res, next) => {
res.locals.token = Verify.getToken(req.user)
next()
}
See the documentation for res.locals for more details.
Example usage:
app.js
const express = require('express')
const app = express()
app.set('view engine', 'pug')
app.use((req, res, next) => {
res.locals.text = 'asdf'
res.locals.token = 'abc'
next()
})
app.get('/', (req, res) => {
res.render('index')
})
app.listen(3000, () => {
console.log('listening on 3000')
})
views/index.pug
doctype html
html
head
title= title
body
h1= text
script.
console.log('#{token}')
I'm very new and I've looked through the archives but just what's going on in this code eludes me. I used express-generator to create a calendar app and now I want to hook it up to MongoDB. The actual connection to Mongo is working, but I can't get it to save a document.
The relevant portion of my global.js (where I'm running my front-end Javascript) looks like this:
$(document).ready(function() {
var ev = new Event({ date: "a6_13_2016", time: 900, description:"Fencing"});
ev.save(function(err) {
if (err) console.log(err);
else console.log("Success!")
})
This is where I'm getting the "TypeError: ev.save is not a function" message. My models/Events.js looks like this:
var mongoose = require('mongoose');
var eventSchema = new mongoose.Schema({
date: String,
time: Number,
description: String
});
module.exports = mongoose.model('Event', eventSchema);
My routes/events.js looks like this:
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Event = require('../models/Events.js');
/* GET /event listing. */
router.get('/', function(req, res, next) {
Event.find(function (err, dates) {
if (err) return next(err);
res.json(dates);
});
});
/*POST event*/
router.post('/', function(req, res, next) {
Event.create(req.body, function (err, post) {
if (err) return next(err);
res.json(post);
});
});
/* GET /event/id */
router.get('/:id', function(req, res, next) {
Event.findById(req.params.id, function (err, post) {
if (err) return next(err);
res.json(post);
});
});
module.exports = router;
I want to save something to test it, but it's giving me ".save is not a function. Other than
var events = require('./routes/events');
app.use('/events', events);
and the code establishing the Mongoose connection my app.js file is boilerplate. What do you think is the problem?
I see
$(document).ready(function() {
Are you trying to use Mongoose in browser?
It's supposed to be used on the server-side.
In browser you need to send AJAX request to the server:
$('#save').click(function() {
$.post('/event', function(response) { console.log(reposne) })
});
On the server you should add a route that will handle your AJAX request, and inside this route you can save your model:
router.post('/event', function(req, res) {
var ev = new Event({ date: "a6_13_2016", time: 900, description:"Fencing"});
ev.save(function(err) {
if (err) console.log(err);
else console.log("Success!")
})
});
Please note that you don't need the 3rd param next in your rotues. It is used only in middlewares
Are you sure that line
var Event = require('../models/Events.js');
has the correct path?
You are creating an ev object from Event function and it seems that ev is undefined, judging from the error description.
If your Event file is not properly loaded you will not have access to .save function.