express router.get() function SyntaxError - javascript

I'm trying to create a route to return JSON data from a JSON-RPC API.
My code:
router.get('/balance', function(req, res, client) {
res.json({
client.getBalance('*', 1, function(err, balance) {
if(err)
console.log(err);
else
console.log('Balance: ', balance);
});
});
});
It's using the npm package node-litecoin. I have required it and created a client var like so:
var client = new litecoin.Client({
host: 'localhost',
port: 9332,
user: 'myaccount',
password: 'mypass'
});
client.getBalance('*', 1, function(err, balance) {
^
SyntaxError: Unexpected token .
Why am I getting this error?

Why am I getting this error?
Because client.getBalance('*', 1, function(err, balance) { cannot be there where you put it.
Lets have a closer look:
res.json({ ... });
The {...} here indicate an object literal. The "content" of the literal has to be a comma separated list of key: value pairs, e.g.
res.json({foo: 'bar'});
You instead put a function call there:
res.json({ client.getBalance(...) });
which simply is invalid.
How can I have the route '/balance' output the client.getBalance() function?
It looks like client.getBalance is an asynchronous function call, hence passing its return value to res.json wouldn't work either. You have to pass the result that you get in the callback to res.json:
router.get('/balance', function(req, res) {
client.getBalance('*', 1, function(err, balance) {
if(err)
console.log(err);
else
console.log('Balance: ', balance);
res.json(balance);
});
});
If you are not very familiar with JavaScript's syntax, I recommend to read the MDN JavaScript Guide.

Related

Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 only on get request page

After building my project. I've noticed I am getting this error after building my application.
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
I am only getting this error message only on pages when I am using a get request.
My server code looks something like this
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, 'build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
});
app.get('/api/global_rankings', function(request, response){
pool.connect((err, db, done) => {
if(err){
return response.status(400).send(err);
}
else{
db.query("some query", function(err, table){
done();
if(err){
return response.status(400).send(err);
}
else{
response.status(201).send({value: table.rows});
}
});
}
});
});
Ive noticed if i delete the first get request, my second get request works fine. However, I need the first get request or-else I get an GET error message when page is not refreshed.
source: https://tylermcginnis.com/react-router-cannot-get-url-refresh/
Is there any way I can fix this?
Thank you
You are getting a response, and the first character is < which I guarantee is an <html> tag because you are getting HTML back and trying to parse it as JSON.
The reason it works if you remove your first request is because * matches any request, including /api/global_rankings so when you have both methods it matches the * and returns an error page.
Switch the method order and see if it does not work like you want then:
app.get('/api/global_rankings', function(request, response){
pool.connect((err, db, done) => {
if(err){
return response.status(400).send(err);
}
else{
db.query("some query", function(err, table){
done();
if(err){
return response.status(400).send(err);
}
else{
response.status(201).send({value: table.rows});
}
});
}
});
});
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, 'build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
});
You have to place the catch-all router /* at the end so it executes only if the route isn't /api/global_rankings:
app.get('/api/global_rankings', function(request, response) { ... }
app.get('/*', function(req, res) { ... });

updated a document with express

I'm trying to use the mongoDB and update the status of a current document. My backend is receiving the routes my mongoDB update isn't going through.
router.post('/orders_drivers', function (req, res, next) {
console.log(req.body);
Order.update({_id:objectId(req.body.id)}, {$set: {driver:req.body.driver, driverReq:false}}).then (function (order) {
console.log('UPDATE new driver');
}).catch (next)
});
when I log the req.body, the ID I receive and the new $set parameters are correct, but the command never goes through. Any suggestions? I don't receive any errors either which I think is strange.
Mongo version is v4.0.2
I have many other routes that all work correctly.
There is no version issue. you are calling then function on non promiseable value.
You need to call a callback function inside of update.
const mongoose = require('mongoose');
router.post('/orders_drivers', function (req, res, next) {
console.log(req.body);
Order.update({
_id: mongoose.Types.ObjectId(req.body.id)
},
{
$set: {
driver:req.body.driver, driverReq:false
}
},
{ new: true }, // If you want to return updated order
function (err, updatedOrder) {
if (err) throw err;
console.log('UPDATE new driver', updatedOrder);
})
});
You don't need to convert req.body.id into mongoose ObjectId if it already is.

Scope access passport-jwt

Can someone explain to me in detail why the route of /profile has access to the user object. I'm currently learning JavaScript and NodeJS your answer will be a big help in my learning Thank you guys.
app.post('/login',function (req, res) {
let email = req.body.email;
let password = req.body.password;
User.getUserByEmail(email, (err, user) => {
if (err) throw err;
if (!user) {
return res.json({
success: false,
message: "User not found!"
});
}
User.comparePassword(password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
var token = jwt.sign(user.toJSON(), config.JWT_SECRET, {
expiresIn: '15m'
});
res.json({
success: true,
token: token,
user: {
id: user._id,
email: user.email
}
});
} else {
return res.json({
success: false,
message: "Password incorrect!"
});
}
})
});
});
app.get('/profile', passport.authenticate('jwt', {
session: false
}), (req, res) => {
res.json({user: req.user});
});
It is because your passport.authenticate() call populates user to req.
From passports.org:
app.post('/login',
passport.authenticate('local'),
function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.redirect('/users/' + req.user.username);
});
It is the same for your route, except your path and authentication method is different.
See the documentation for more info: http://www.passportjs.org/docs/authenticate/
Some background
The function app.get takes an url and one or many callbacks with (req, res, next) => {} as their signature
The callbacks are executed one after the other. In anyone of these callbacks you can modify the req object and it will "propagate" to the next callbacks
To switch from a callback to the next one, you call next
In your case
The call to passport.authenticate('jwt', {sessions: false}) returns a callback, that's executed before you send the json response.
That callback itself athenticates the user, then "inject" its value into the req object.
As I mentioned before, this req will "propagate" to the next callback. And that's why when you send your json response, it req already contains the user key

how to find out the exact name of error thrown in mysql node.js

I am building a server with node.js (express) and mysql felix.
my problem is that sometime i have a query that will return a duplicate error.
I have tried everything on mind to try and catch this error without luck, the program crashes.
This is my code:
this.addReservation = function(req, res, next) {
var json = JSON.parse(req.body['reservation']);
var post = {user1: json.player1, user2: json.player2, courtId: json.id, hour: json.hour, date: json.date};
var giveback = {u1_first: req.user.firstName, u1_last: req.user.lastName, user1: json.player1, user2: json.player2};
connection.query('insert into ordering set ?', post, function(err, result){
if (err){
throw err;
return res.send(500);
}
else
return res.json({res: giveback})
//return res.send(200);
});
};
now i have tried wrapping this query with try and catch. didn't help.
i tried to enter this row:
connection.on('error', function() {console.log();}); didn't help neither.
i tried putting this line in other places still not helping.
the error that is thrown in my console is: Error: ER_DUP_ENTRY.
what am i doing wrong? should i use "on" on something different than 'error'?
that only thing that helped me is:
process.on('uncaughtException', function(err) {
// handle the error safely
console.log(err);
});
but this is very bad as i do know the error that is caused and i wish to deal with it so this is a very bad solution for me.
please help me thanks. i am using mysql felix library.
this.addReservation = function(req, res, next) {
var json = JSON.parse(req.body['reservation']);
var post = {user1: json.player1, user2: json.player2, courtId: json.id, hour: json.hour, date: json.date};
var giveback = {u1_first: req.user.firstName, u1_last: req.user.lastName, user1: json.player1, user2: json.player2};
connection.query('insert into ordering set ?', post, function(err, result){
if (err){
console.log('exact name of error thrown '+err);
return res.send(500);
}
else
return res.json({res: giveback})
//return res.send(200);
});
};

Sending back a JSON response when failing Passport.js authentication

I'm using Node.js as a backend API server for an iPhone client. I'm using Passport.js to authenticate with a local strategy. The relevant code is below:
// This is in user.js, my user model
UserSchema.static('authenticate', function(username, password, callback) {
this.findOne({ username: username }, function(err, user) {
if (err){
console.log('findOne error occurred');
return callback(err);
}
if (!user){
return callback(null, false);
}
user.verifyPassword(password, function(err, passwordCorrect){
if (err){
console.log('verifyPassword error occurred');
return callback(err);
}
if (!passwordCorrect){
console.log('Wrong password');
return callback(err, false);
}
console.log('User Found, returning user');
return callback(null, user);
});
});
});
and
// This is in app.js
app.get('/loginfail', function(req, res){
res.json(403, {message: 'Invalid username/password'});
});
app.post('/login',
passport.authenticate('local', { failureRedirect: '/loginfail', failureFlash: false }),
function(req, res) {
res.redirect('/');
});
Right now, I have managed to redirect a failed login to /loginfail, where I send back some JSON to the iPhone client. However, this doesn't have enough granularity. I want to be able to send back the appropriate errors to the iPhone client, such as: "No user found" or "Password is wrong". With my existing code, I don't see how this can be accomplished.
I tried to follow the examples for a custom callback on the passport.js site, but I just can't get it to work due to lack of node understanding. How could I modify my code so that I'd be able to send back a res.json with an appropriate error code/message?
I am trying something like this now:
// In app.js
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err) }
if (!user) {
console.log(info);
// *** Display message without using flash option
// re-render the login form with a message
return res.redirect('/login');
}
console.log('got user');
return res.json(200, {user_id: user._id});
})(req, res, next);
});
// In user.js
UserSchema.static('authenticate', function(username, password, callback) {
this.findOne({ username: username }, function(err, user) {
if (err){
console.log('findOne error occurred');
return callback(err);
}
if (!user){
return callback(null, false);
}
user.verifyPassword(password, function(err, passwordCorrect){
if (err){
return callback(err);
}
if (!passwordCorrect){
return callback(err, false, {message: 'bad password'});
}
console.log('User Found, returning user');
return callback(null, user);
});
});
});
But back when I try to console.log(info), it just says undefined. I don't know how to get this custom callback working...Any help would be appreciated!
I had a similar issue with Passport and failed login responses. I was building an API, and wanted all responses to be returned as JSON. Passport responds to an invalid password with status: 401 and body: Unauthorized. That's just a text string in the body, not JSON, so it broke my client which expected all JSON.
As it turns out, there is a way to make Passport just return the error to the framework instead of trying to send a response itself.
The answer is to set failWithError in the options passed to authenticate:
https://github.com/jaredhanson/passport/issues/126#issuecomment-32333163
From jaredhanson's comment in the issue:
app.post('/login',
passport.authenticate('local', { failWithError: true }),
function(req, res, next) {
// handle success
if (req.xhr) { return res.json({ id: req.user.id }); }
return res.redirect('/');
},
function(err, req, res, next) {
// handle error
if (req.xhr) { return res.json(err); }
return res.redirect('/login');
}
);
This will invoke the error handler after Passport calls next(err). For my app, I wrote a generic error handler specific to my use case of just providing a JSON error:
// Middleware error handler for json response
function handleError(err,req,res,next){
var output = {
error: {
name: err.name,
message: err.message,
text: err.toString()
}
};
var statusCode = err.status || 500;
res.status(statusCode).json(output);
}
Then I used it for all api routes:
var api = express.Router();
...
//set up some routes here, attached to api
...
// error handling middleware last
api.use( [
handleError
] );
I didn't find the failWithError option in the documentation. I stumbled upon it while tracing through the code in the debugger.
Also, before I figured this out, I tried the "custom callback" mentioned in the #Kevin_Dente answer, but it didn't work for me. I'm not sure if that was for an older version of Passport or if I was just doing it wrong.
I believe the callback function that your 'authenticate' static calls (called 'callback' in your code) accepts a 3rd parameter - "info" - which your code can provide. Then, instead of passing in the { failureRedirect: ...} object, pass in a function which takes 3 arguments - err, user, and info. The "info" you provided in your authenticate method will be passed to this callback.
Passport calls this scenario "custom callback". See the docs here:
http://passportjs.org/guide/authenticate/
There is an official documentation for Custom Callback:
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
https://github.com/passport/www.passportjs.org/blob/master/views/docs/authenticate.md
As per the official documentation of Passport you may use custom callback function to handle the case of failed authorization and override the default message.
If you are developing REST API and then you would want to send out pretty JSON response something as below:
{
"error": {
"name": "JsonWebTokenError",
"message": "invalid signature"
},
"message": "You are not authorized to access this protected resource",
"statusCode": 401,
"data": [],
"success": false
}
I was using Passport JWT authentication to secure some of my routes and was applied the authMiddleware as below:
app/middlewares/authMiddleware.js
const express = require('express');
const router = express.Router();
const passport = require('passport');
const _ = require('lodash');
router.all('*', function (req, res, next) {
passport.authenticate('local', function(err, user, info) {
// If authentication failed, `user` will be set to false. If an exception occurred, `err` will be set.
if (err || !user || _.isEmpty(user)) {
// PASS THE ERROR OBJECT TO THE NEXT ROUTE i.e THE APP'S COMMON ERROR HANDLING MIDDLEWARE
return next(info);
} else {
return next();
}
})(req, res, next);
});
module.exports = router;
app/routes/approutes.js
const authMiddleware = require('../middlewares/authMiddleware');
module.exports = function (app) {
// secure the route by applying authentication middleware
app.use('/users', authMiddleware);
.....
...
..
// ERROR-HANDLING MIDDLEWARE FOR SENDING ERROR RESPONSES TO MAINTAIN A CONSISTENT FORMAT
app.use((err, req, res, next) => {
let responseStatusCode = 500;
let responseObj = {
success: false,
data: [],
error: err,
message: 'There was some internal server error',
};
// IF THERE WAS SOME ERROR THROWN BY PREVIOUS REQUEST
if (!_.isNil(err)) {
// IF THE ERROR IS REALTED TO JWT AUTHENTICATE, SET STATUS CODE TO 401 AND SET A CUSTOM MESSAGE FOR UNAUTHORIZED
if (err.name === 'JsonWebTokenError') {
responseStatusCode = 401;
responseObj.message = 'You are not authorized to access this protected resource';
}
}
if (!res.headersSent) {
res.status(responseStatusCode).json(responseObj);
}
});
};
You can do that without custom callbacks using property passReqToCallback in your strategy definition:
passport.use(new LocalStrategy({passReqToCallback: true}, validateUserPassword));
Then you can add your custom auth error code to the request in your strategy code:
var validateUserPassword = function (req, username, password, done) {
userService.findUser(username)
.then(user => {
if (!user) {
req.authError = "UserNotFound";
return done(null, false);
}
And finally you can handle these custom errors in your route:
app.post('/login', passport.authenticate('local', { failWithError: true })
function (req, res) {
....
}, function(err, req, res, next) {
if(req.autherror) {
res.status(401).send(req.autherror)
} else {
....
}
}
);
A short workaround is to emulate the Flash method call which intended originally to support connect-flash and to use this method to return the JSON object.
first define the "emulator":
var emulateFlash = function (req, res, next) {
req.flash = (type, message) => {
return res.status(403).send({ status: "fail", message });
}
next();
}
this will inject the flash method which will send the error JSON object upon failure.
In the route do the following:
1st, use the emulator across the board using:
router.use(emulateFlash);
One can instead use the emulateFlash method on each route needed.
2nd, on the route when using authenticate, specify the failureFlash option using a message:
router.route("/signin")
.post(.authenticate('local', { session: false, failureFlash: "Invalid email or password."}), UsersController.signIn);
I tested this for both failed authentication as well as successful and found it working. Looking at the code I could not find any other way to return an object other than implementing the callback method which requires much more work.

Categories