I'm new to Node.JS and I'm trying to write an API which stores user data in a database after checking if the username already exists.
Below is my app.js code
const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const sqlHelper = require('./sqlHelper');
app.use(bodyParser.json());
app.post('/registeruser',(req,res)=>{
const userName = req.body.username;
const password = req.body.password;
const firstName = req.body.firstname;
const lastName = req.body.lastname;
const userDetail = {
userName,
password,
firstName,
lastName
}
sqlHelper.addUserSQL(userDetail,res);
res.send("User Registerd Seccesfuly");
})
const server = http.createServer(app);
server.listen(3000);
Below is my sqlHelper.js code
const mysql = require('mysql2');
const addUserSQL = (userDetail,res) => {
const con = mysql.createConnection({
host:'localhost',
user:'root',
password:'mysqlpw',
multipleStatements: true
});
con.connect(function(err){
if(err)
throw err
console.log("CHECKING IF USER ALREADY EXIST");
let sql = `USE mydatabase; SELECT * FROM usertable WHERE username=?`;
con.query(sql,[userDetail.userName],function(err,result){
if(err)
throw err;
if(result[1]!=[]){
res.send("ERROR: USERNAME ALREADY EXISTS");
}
})
})
}
module.exports={addUserSQL};
When there is a request with a username that is already in my database I get the following response User registered successfully instead of ERROR: USERNAME ALREADY EXISTS and a error in terminal
Cannot set headers after they are sent to the client.
How can I write this code in a proper way to check if a username already exists and send a response back?
A straight answer your question is NO
You should never do res.send from function being called.
Instead,You should return error from your sqlhelper code.
Try this code:
app.post('/registeruser',async (req,res)=>{
const userName = req.body.username;
const password = req.body.password;
const firstName = req.body.firstname;
const lastName = req.body.lastname;
const userDetail = {
userName,
password,
firstName,
lastName
}
const {err} = await sqlHelper.addUserSQL(userDetail);
if(err) return res.status(500).send(err);
res.send("User Registerd Seccesfuly");
})
Changes in sqlHelper file:
const mysql = require('mysql2/promise');
const options = {
host:'localhost',
user:'root',
password:'mysqlpw',
multipleStatements: true
};
const addUserSQL =async (userDetail) => {
const connection = await mysql.createConnection(options);
const query = `USE mydatabase; SELECT * FROM usertable WHERE username=?`;
const [rows, fields] = await connection.execute(query, [userDetail.userName]);
if(rows?.length>0){
return {err: "ERROR: USERNAME ALREADY EXISTS" };
}else{
//code to create user entry in your db
}
}
module.exports={addUserSQL};
Related
//userRoutes.js
const express = require("express");
const { registerUser } = require("../controller/userController");
const router = express.Router();
router.post("/", registerUser);
module.exports = router;
//server.js
const express = require("express");
const dotenv = require("dotenv");
const app = express();
// database
const connectDb = require("./db/db");
require("colors");
// router
const userRoute = require("./routes/userRoutes");
const port = process.env.PORT || 8080;
dotenv.config();
connectDb();
app.use(express.json());
app.use("/api/users", userRoute);
app.listen(port, () => {
console.log("");
console.log(
` Running on Port ${port} in ${process.env.MODE} Mode `.yellow.inverse
);
console.log("");
});
//userController.js
const User = require("../models/userModel");
const asyncHandler = require("express-async-handler");
const registerUser = asyncHandler(async (req, res) => {
console.log(req.body);
const { firstName, lastName, email, password } = req.body;
const exists = User.findOne({ email });
if (exists) {
res.status(400);
throw new Error("User Already Exists!");
}
const user = await User.create({ firstName, lastName, email, password });
if (user) {
res.status(200).json({
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
isAdmin: user.isAdmin,
});
} else {
res.status(404);
throw new Error("User Not Created");
}
});
module.exports = { registerUser };
SyntaxError: Unexpected token } in JSON at position 118
at JSON.parse (<anonymous>)
`enter code here` at parse (D:\tutorial\shppingapp\node_modules\body-parser\lib\types\json.js:89:19)
at D:\tutorial\shppingapp\node_modules\body-parser\lib\read.js:121:18
at invokeCallback (D:\tutorial\shppingapp\node_modules\raw-body\index.js:224:16)
at done (D:\tutorial\shppingapp\node_modules\raw-body\index.js:213:7)
at IncomingMessage.onEnd (D:\tutorial\shppingapp\node_modules\raw-body\index.js:273:7)
at IncomingMessage.emit (node:events:406:35)
at endReadableNT (node:internal/streams/readable:1331:12)
at processTicksAndRejections (node:internal/process/task_queues:83:21)
I think you are getting this error because of not sending well req in postman you have to send req as your User Schema defined in the model and once send well formated in postman body>text>json...
I'm trying to create a Login functionality using express-jwt, and using the middleware function in my app.js file. But whenever I'm trying to send a get request using the postman, it sending request for infinite of time and never returns back any error or success message.
I'm using dynamoDB as database.
here's my Login.js file
const AWS = require("aws-sdk");
const express = require("express");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
require("dotenv").config();
AWS.config.update({ region: "us-east-2" });
const docClient = new AWS.DynamoDB.DocumentClient();
const router = express.Router();
router.post("/login", (req, res) => {
user_type = "customer";
const email = req.body.email;
docClient.get(
{
TableName: "users",
Key: {
user_type,
email,
},
},
(err, data) => {
if (err) {
res.send("Invalid username or password");
} else {
if (data && bcrypt.compareSync(req.body.password, data.Item.password)) {
const token = jwt.sign(
{
email: data.Item.email,
},
process.env.SECRET,
{ expiresIn: "1d" }
);
res.status(200).send({ user: data.Item.email, token: token });
} else {
res.status(400).send("Password is wrong");
}
}
}
);
});
module.exports = router;
Here's my jwt.js file:
const expressJwt = require("express-jwt");
require("dotenv").config();
function authJwt() {
const secret = process.env.SECRET;
return expressJwt({
secret,
algorithms: ["HS256"],
});
}
module.exports = authJwt;
And I'm trying to use the expressJwt like this in my app.js file:
app.use(authJwt); //If I'm not using this, then the code works fine without API protection
Can Anyone tell me what's wrong with my code?
Any help from your side is appreciated.
Remove function from your jwt.js ,it should look like this
const expressJwt = require('express-jwt');
const secret = process.env.secret
const authJwt = expressJwt({
secret,
algorithms:['HS256']
})
module.exports = authJwt;
userSchema.statics.findByCredentials = async (email, password) =>{
const user =await User.findOne({ email })
if(!user){
throw new Error("Unable to Login!")
}
const isMatch = await bcrypt.compare(password, user.password)
if (!isMatch){
throw new Error("Invalid to Login!!")
}
return user
}
const User = new mongoose.model("User",userSchema)
module.exports = User
In users i have set the routes properly too:
router.post("/users/login", async (req,res) => {
try{
const user = await User.findByCredentials(req.body.email, req.body.password)
res.send(user)
}
catch(err){
res.status(400).send()
}
})
But i get 400 Bad request error. The route is catching the error.
findByCredentials is not working?
What is my mistake??
Please can anyone look at this code lines... One is working while the other wouldn't work. I am trying to figure out the reason why. in one case, there is a username object in the model for users. while in the other one there is name object as against username. Each model both have a phone object. So in the first case, the user is set up to log in with phone and password.
In this case, the server returns bad request error. Please see code below
//routes/User.js
const express = require('express');
const userRouter = express.Router();
const passport = require('passport');
const passportConfig = require('../passport');
const JWT = require('jsonwebtoken');
const User = require('../models/User');
const Todo = require('../models/Transaction');
const signToken = userID =>{
return JWT.sign({
iss : "comparelight",
sub : userID
},"comparelight",{expiresIn : "1h"});
}
userRouter.post('/register',(req,res)=>{
const { phone,password,name, role, disco, meter, email } = req.body;
User.findOne({phone},(err,user)=>{
if(err)
res.status(500).json({message : {msgBody : "Error has occured", msgError: true}});
if(user)
res.status(400).json({message : {msgBody : "Username is already taken", msgError: true}});
else{
const newUser = new User({phone,password,name, role, disco, meter, email});
newUser.save(err=>{
if(err)
res.status(500).json({message : {msgBody : "Error has occured", msgError: true}});
else
res.status(201).json({message : {msgBody : "Account successfully created", msgError: false}});
});
}
});
<!-- begin snippet: js hide: false console: true babel: false -->
// passport.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const JwtStrategy = require('passport-jwt').Strategy;
const User = require('./models/User');
const cookieExtractor = req =>{
let token = null;
if(req && req.cookies){
token = req.cookies["access_token"];
}
return token;
}
// authorization
passport.use(new JwtStrategy({
jwtFromRequest : cookieExtractor,
secretOrKey : "comparelight"
},(payload,done)=>{
User.findById({_id : payload.sub},(err,user)=>{
if(err)
return done(err,false);
if(user)
return done(null,user);
else
return done(null,false);
});
}));
// authenticated local strategy using phone and password
passport.use(new LocalStrategy((phone,password,done)=>{
User.findOne({phone},(err,user)=>{
// something went wrong with database
if(err)
return done(err);
// if no user exist
if(!user)
return done(null,false);
// check if password is correct
user.comparePassword(password,done);
});
}));
But in the other case, the user is set up to sign in with username and password. And this works. Please see code below.
//routes/User.js
const express = require('express');
const userRouter = express.Router();
const passport = require('passport');
const passportConfig = require('../passport');
const JWT = require('jsonwebtoken');
const User = require('../models/User');
const Todo = require('../models/Transaction');
const signToken = userID =>{
return JWT.sign({
iss : "comparelight",
sub : userID
},"comparelight",{expiresIn : "1h"});
}
userRouter.post('/register',(req,res)=>{
const { username,password,phone, role, disco, meter, email } = req.body;
User.findOne({username},(err,user)=>{
if(err)
res.status(500).json({message : {msgBody : "Error has occured", msgError: true}});
if(user)
res.status(400).json({message : {msgBody : "Username is already taken", msgError: true}});
else{
const newUser = new User({phone,password,username, role, disco, meter, email});
newUser.save(err=>{
if(err)
res.status(500).json({message : {msgBody : "Error has occured", msgError: true}});
else
res.status(201).json({message : {msgBody : "Account successfully created", msgError: false}});
});
}
});
});
userRouter.post('/login',passport.authenticate('local',{session : false}),(req,res)=>{
if(req.isAuthenticated()){
const {_id,username,role} = req.user;
const token = signToken(_id);
res.cookie('access_token',token,{httpOnly: true, sameSite:true});
res.status(200).json({isAuthenticated : true,user : {username,role}});
}
});
// passport.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const JwtStrategy = require('passport-jwt').Strategy;
const User = require('./models/User');
const cookieExtractor = req =>{
let token = null;
if(req && req.cookies){
token = req.cookies["access_token"];
}
return token;
}
// authorization
passport.use(new JwtStrategy({
jwtFromRequest : cookieExtractor,
secretOrKey : "comparelight"
},(payload,done)=>{
User.findById({_id : payload.sub},(err,user)=>{
if(err)
return done(err,false);
if(user)
return done(null,user);
else
return done(null,false);
});
}));
// authenticated local strategy using username and password
passport.use(new LocalStrategy((username,password,done)=>{
User.findOne({username},(err,user)=>{
// something went wrong with database
if(err)
return done(err);
// if no user exist
if(!user)
return done(null,false);
// check if password is correct
user.comparePassword(password,done);
});
}));
Thanks.
I'm developing an app for Shopify. Currently under development stage. Until now, I have successfully managed to authorise the app and then redirect it back to admin page using the Embedded App SDK. However, when I return to the admin page, it gives me an error saying Request origin cannot be verified.
The console shows Failed to load resource: the server responded with a status of 403 (Forbidden)
The URL in the console is something like this https://myshop.myshopify.com/admin/apps/dfdjf4343343434343434bfdf/shopify/shopify/callback?code=ffdfdffd&hmac=fdfdfdfdfdfdfdfdfddfdfdfdfdf&shop=myshop.myshopify.com&state=151193864548800×tamp=1511938648
The fdfdfdfdfdfdfdfdfddfdfdfdfdf are just random characters that I've replaced instead of a hash. FYI - I've removed the app name and user profile name and avatar from the image.
This is happening because, you are unable to match state, that is set in cookie, while responding with redirect url
const ShopifyToken = require('shopify-token')
const forwardingAddress = process.env.HOST
const shopifyToken = new ShopifyToken({
sharedSecret: process.env.SHOPIFY_API_SECRET,
redirectUri: forwardingAddress + '/shopify/callback',
apiKey: process.env.SHOPIFY_API_KEY
})
const shopify = {
// use this for authentication
auth: (req, res, next) => {
const shop = req.query.shop
if (!shop) {
return res.status(400).send('Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request')
}
const shopRegex = /^([\w-]+)\.myshopify\.com/i
const shopName = shopRegex.exec(shop)[1]
const state = shopifyToken.generateNonce()
const url = shopifyToken.generateAuthUrl(shopName, scopes, state)
res.cookie('state', state)
res.redirect(url)
},
// use this as your callback function
authCallback: async (req, res) => {
const { shop, hmac, code, state } = req.query
const stateCookie = cookie.parse(req.headers.cookie).state
if (state !== stateCookie) {
// you are unable to set proper state ("nonce") in this case, thus you are getting this error
return res.status(403).send('Request origin cannot be verified')
}
if (!shop || !hmac || !code) {
res.status(400).send('Required parameters missing')
}
let hmacVerified = shopifyToken.verifyHmac(req.query)
console.log(`verifying -> ${hmacVerified}`)
// DONE: Validate request is from Shopify
if (!hmacVerified) {
return res.status(400).send('HMAC validation failed')
}
const accessToken = await shopifyToken.getAccessToken(shop, code)
const shopRequestUrl = 'https://' + shop + '/admin/shop.json'
const shopRequestHeaders = {
'X-Shopify-Access-Token': accessToken
}
try {
const shopResponse = await request.get(shopRequestUrl, { headers: shopRequestHeaders })
res.status(200).end(shopResponse)
} catch (error) {
res.status(error.statusCode).send(error.error.error_description)
}
}
}
Simple as this is, also make sure that the protocol matches from what you typed in to start the app install.
If you accidentally use http for http://you.ngrok.io/ but your callback redirects to https (i.e. https://you.ngrok.io/auth/callback), the OAuth handshake will fail.
const express = require('express');
const router = express.Router();
const dotenv = require('dotenv').config();
const cookie = require('cookie');
const requestPromise = require('request-promise');
const ShopifyToken = require('shopify-token');
const scopes = "write_products";
const forwardingAddress = process.env.HOST;
var shopifyToken = new ShopifyToken({
sharedSecret: process.env.SHOPIFY_API_SECRET,
redirectUri: forwardingAddress + '/shopify/callback',
apiKey: process.env.SHOPIFY_API_KEY
})
router.get('/shopify', (req, res) => {
const shop = req.query.shop;
if (!shop) {
return res.status(400).send('Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request')
}
const shopRegex = /^([\w-]+)\.myshopify\.com/i
const shopName = shopRegex.exec(shop)[1]
const state = shopifyToken.generateNonce();
const url = shopifyToken.generateAuthUrl(shopName, scopes, state);
res.cookie('state', state);
res.redirect(url);
});
router.get('/shopify/callback', (req, res) => {
const { shop, hmac, code, state } = req.query;
const stateCookie = cookie.parse(req.headers.cookie).state;
if (state !== stateCookie) {
// you are unable to set proper state ("nonce") in this case, thus you are getting this error
return res.status(403).send('Request origin cannot be verified')
}
if (!shop || !hmac || !code) {
res.status(400).send('Required parameters missing')
}
let hmacVerified = shopifyToken.verifyHmac(req.query)
console.log(`verifying -> ${hmacVerified}`)
// DONE: Validate request is from Shopify
if (!hmacVerified) {
return res.status(400).send('HMAC validation failed')
}
const accessToken = shopifyToken.getAccessToken(shop, code);
const shopRequestUrl = 'https://' + shop + '/admin/products.json'
const shopRequestHeaders = {
'X-Shopify-Access-Token': accessToken
}
try {
const shopResponse = requestPromise.get(shopRequestUrl, { headers: shopRequestHeaders })
res.status(200).send(shopResponse)
} catch (error) {
res.status(error.statusCode).send(error.error.error_description)
}
});
module.exports = router;