Axios 404 when requesting from routes folder - javascript

I have a server.js file in Express and Node.js that contains the majority of my back-end code, outside of my database config file.
The file is quite long and to improve maintainability, I would like to make it modular by splitting various components into their own files that can be imported.
I have attempted to move a database endpoint as a starting point into its own file called auth.js, located in the routes folder. The file is set up as follows:
const express = require('express');
const router = express.Router();
const db = require('../config/db');
const crypto = require("crypto"); // set up crypto middleware for hashing password and checking password hashes
const salt = crypto.randomBytes(256).toString("hex"); // create a hash salt/pepper
const iterations = 1000; // number of iterations to jumble the hash
const hashSize = 64; //set up char length of hash
const hashAlgorithm = "sha256"; // which hashing algorithm will be used
//This function returns a hash of the password, combined with the pepper and the salt.
function PasswordHash(password, salt) {
//PEPPER MUST BE MOVED TO ENV FILE WHEN READY
const pepper = "ec3fd71d14f7cab570fc94df34e60e4d8c80cdff4d1dde66c74b10ae576b88239315295adabaced63b05104bbf8d2f2f92a24aeebe8444861ba1b7efc73dafdeda6fe2bf6e7288f959832d5db953a7eab0b37ef8ad126f94616b0c1e7b3b0ce7418dff91afaa78401dacce6aee72649840e26a01d75bfac69acf8d0dd50aaddebb9397150bb0f88795cde94ea3d03fec2992fc3b5c3c7bbd8de3f8f7d693cdcca879d9aefd6e02d4457217928091a731c08f83f9927f9b19ca34ab589dd02ecc40e336e067a1f2e072ec2b3a93617ded73028ed5bc5d55f011ba5a53099312f06d649fa06fdbf49e81c8f9a81f113f95cd416d230c2cb6056189c77f889dc83d";
return crypto.pbkdf2Sync (
password,
salt + pepper,
iterations,
hashSize,
hashAlgorithm
).toString("hex");
};
// login route
router.post('/signin', (req, res) => {
const { email, password } = req.body;
// Check all emails against input
db.query(selectEmail, [email], (err, rows) => {
if (err) throw err;
// If email exists
if (rows.length > 0) {
// If password with salt and compares to database
if (PasswordHash(password, rows[0].salt) == rows[0].password) {
// Create session
req.session.firstName = rows[0].first_name;
req.session.lastName = rows[0].last_name;
req.session.username = rows[0].user_name;
req.session.ProfilePicture = rows[0].profile_picture;
console.log('Session created:', req.session); // Print session
res.send('Login successful');
}
// If password is incorrect
else {
res.send('Email or password are incorrect');
}
}
// If email does not exist
else {
res.send('Email or password are incorrect');
};
});
});
module.exports = router;
This is then used in the main server.js file by requiring the auth.js file and using it with the route '/signin':
const authRoutes = require('./routes/auth');
app.use('/signin', authRoutes);
Finally, I make a request on my React front-end application to the /signin route.
const validateRow = () => {
// Validate login
axios.post('http://localhost:8080/signin', {
email: emailInput,
password: passwordInput
})
.then((res) => {
setMessage(res.data);
//If validation passed
if (res.data === 'Login successful') {
navigate('/directory')
};
});
};
To add some context this is for a login form and validates login data inputted into the form against rows found in the database. This worked as intended until I moved the endpoint into a separate file I now receive:
AxiosError {message: 'Request failed with status code 404', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
on my front end. I would like to know how to resolve this issue.

The issue is that app.use('/signin', authRoutes) makes an endpoint be "/signin/signin" not just "/signin" which you are trying to request. The simplest solution would be to change link you pass in axios.post function to "http://localhost:8080/signin/signin".

Try using relative path as suggested in this (possible duplicate):
I don't understand why my axios post request isn't working - 404 not found

You need to listen to the port 8080
const app = express()
const port = 8080
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})

Related

Having issues with app.post, results in Cannot Get /

I'm trying to create a sign-up page where users can enter information, however, I'm having issues with "app.post" properly working. This is what I have so far:
const express = require("express");
const db = require("./dbConnectExec.js")
const app = express();
app.use(express.json());
app.listen(5000, () => {
console.log('App is running on port 5000');
});
app.get("/hi", (req,res) => {
res.send("Hello world.");
});
app.get("/", (req,res) => {
res.send("API is running.");
});
// app.post();
// app.put();
app.post("/customers", async(req, res) => {
// res.send("/contacts called");
// console.log("request body", req.body)
let nameFirst = req.body.nameFirst;
let nameLast = req.body.nameLast;
let email = req.body.email;
let password = req.body.password;
let emailCheckQuery = `
SELECT customer_email
FROM Customer
WHERE customer_email = '${email}'`;
let existingUser = await db.executeQuery(emailCheckQuery);
console.log("existing user", existingUser);
if(existingUser[0]){return res.status(409).send("duplicate email")};
})
When I attempt to add a user through Postman, for example:
{"nameFirst": "Robert",
"nameLast": "Redford",
"email": "rob#mail.com",
"password": "asdfasdf"}
I end up with "Cannot GET /customers"
You have no GET handler for /customers only a POST handler
In postman you can change your request from a GET to a POST request. Once you do it should hit this route endpoint.
note:
"GET is used for viewing something, without changing it, while POST is used for changing something. For example, a search page should use GET to get data while a form that changes your password should use POST . Essentially GET is used to retrieve remote data, and POST is used to insert/update remote data."

Bind problem in SQL query in Node, Express, Mysql2 app

I have been following a tutorial on setting up REST APIs in Node, using Express for an app that accesses an existing MariaDB database. My version only needs to read data and I have the DB co-located with the Node application (same host).
My goal for this entry-level example is to just access the data, using static SQL, so I can see it rendered in the web page by the JSON pritifier.
[Next, I want to present the data in a table (EJS?). Later, when I can get that to work, I'll add form controls (React?) to let a user specify start and end date bounds for the SQL query. Finally I'll aim to render the data as a line graph (D3js).]
The tutorial runs the web server successfully (it returns 'OK' on the base URL), but when I go to URL/solarData it tries an async function to getMultiple rows from the DB, it responds:
Bind parameters must not contain undefined. To pass SQL NULL specify JS null TypeError: Bind parameters must not contain undefined. To pass SQL NULL specify JS null
at /SunnyData/solarViz/node_modules/mysql2/lib/connection.js:628:17
at Array.forEach (<anonymous>)
at Connection.execute (/SunnyData/solarViz/node_modules/mysql2/lib/connection.js:620:22)
at /SunnyData/solarViz/node_modules/mysql2/promise.js:120:11
at new Promise (<anonymous>)
at PromiseConnection.execute (/SunnyData/solarViz/node_modules/mysql2/promise.js:117:12)
at Object.query (/SunnyData/solarViz/services/db.js:6:40)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async Object.getMultiple (/SunnyData/solarViz/services/solarData.js:7:16)
at async /SunnyData/solarViz/routes/solarData.js:8:14
app.js:61
./app.js
const express = require('express');
const app = express();
const port = process.env.PORT || 3800;
const solarDataRouter = require('./routes/solarData');
app.use(express.json());
app.use(
express.urlencoded({
extended: true,
})
);
app.get('/', (req, res) => {
res.json({'message': 'ok'});
})
app.use('/solarData', solarDataRouter);
/* Error handler middleware */
app.use((err, req, res, next) => {
const statusCode = err.statusCode || 500;
console.error(err.message, err.stack);
res.status(statusCode).json({'message': err.message});
return;
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
});
./routes/solarData.js
const express = require('express');
const router = express.Router();
const solarData = require('../services/solarData');
/* GET solar data. */
router.get('/', async function(req, res, next) {
try {
res.json(await solarData.getMultiple(req.query.page));
} catch (err) {
console.error(`Error while getting solar data `, err.message);
next(err);
}
});
module.exports = router;
./config.js
const env = process.env;
const config = {
db: {
host: env.SUNNY_HOST,
user: env.SUNNY_USER,
password: env.SUNNY_PW,
database: env.SUNNY_DB,
},
listPerPage: env.LIST_PER_PAGE,
};
module.exports = config;
./services/solarData.js
const db = require('./db');
const helper = require('../helper');
const config = require('../config');
async function getMultiple(page = 1){
const offset = helper.getOffset(page, config.listPerPage);
const rows = await db.query(
`SELECT * FROM DTP LIMIT ?,?`, [offset, config.listPerPage]
);
const data = helper.emptyOrRows(rows);
const meta = {page};
return {
data,
meta
}
}
module.exports.getMultiple = getMultiple;
./services/db.js
const mysql = require('mysql2/promise');
const config = require('../config');
async function query(sql, params) {
const connection = await mysql.createConnection(config.db);
const [results, ] = await connection.execute(sql, params);
return results;
}
module.exports = {
query
}
I've left out the ./helper.js
Everything runs fine until I direct the webpage to /solarData. At that point I get the Debug Console (vscode) mentioned up-front
Searching seems to point at a mysql2 shortcoming/bug but not at a practical solution
If you respond, please describe the 'bind' mechanism, as I'm not sure what's going on.
Hope I've put enough info in. Please ask if I need to add anything else.
The error says
Bind parameters must not contain undefined.
It means that in the file ./services/solarData.js on the line
const rows = await db.query(
`SELECT * FROM DTP LIMIT ?,?`, [offset, config.listPerPage]
);
Some of the 2 variables is undefined, you need to check offset and config.listPerPage to be defined.
Just use
console.log('offset: ' + offset)
console.log('listPerPage: ' + config.listPerPage)
and you will find out what is undefined in your case

Using express-formidable to get multipart data , but it makes simple post requests with request body run forever

app.js
const express = require('express')
const app = express()
const app = express()
const PORT = process.env.SERVER_PORT || 8080
app.use(express.json())
app.use(express.urlencoded({
extended : true
}))
app.use(formidableMiddleware());
app.listen(PORT, () => {
console.log(`The application is up and running on ${PORT}`)
})
controller.js
This contains the controller that takes base64 encoded image in formdata and that can be accessed with filename property (This is one controller which is working fine with formidable)
const uploadProfilePic = async (req, res) => {
let strArr = req.fields.filename.split(',')
let buffer = new Buffer(strArr[1], 'base64')
let filename =
Date.now().toString() + '' + strArr[0].split('/')[1].split(';')[0]
try {
req.user.profile = buffer
req.user.filename = filename
await req.user.save()
return res.status(200).json(
customMessage(true, {
message: 'Successfully uploaded',
}),
)
} catch (error) {
return res.status(500).status(internalServerError)
}
}
controller2.js This controller is not working properly, it does not even run when we use express-formidable and the post request route to which this controller is binded to, runs forever, but if we pass no request body then it runs perfectly or if we comment out:
//app.use(express-formidable);
//In app.js
then it runs properly but then controller.js doesnt run.
const updateUserData = async (req, res) => {
try {
const {_id, email, name, username, bio, code, platform, languages } = req.body
if (username === undefined || code === undefined || !platform || !languages)
return res
.status(400)
.json(customMessage(false, 'Please Satisy Validations'))
let user = req.user
let user1 = await UserModel.findById(_id)
user1.username = username;
user1.code = code;
user1.bio = bio;
user1.platform = platform;
user1.languages = languages;
if (!user) return res.status(500).json(internalServerError())
else {
await user1.save()
console.log
return res
.status(200)
.json(customMessage(true, `user with ${email} updated`))
}
} catch (error) {
console.log(error)
return res.status(500).json(internalServerError())
}
}
Okay I found a way to send requests through the multipart/form data and the application/json without breaking any thing. I actually spent 2 hours trying to figure out what happened and how to solve the problem. I discovered that the package "express-formidable" is no longer being maintained and has been closed down. Then I also found another package which of course solved the problem just about now "express-formidable-v2" which I believe is the continuation of the former package.
Check this https://github.com/Abderrahman-byte/express-formidable-v2 out, It is a fork of "express-formidable" package
Now you have access to your {req.fields} and {req.body}

Validating Kentico Cloud webhooks signatures in Express.js

How to validate webbooks signature using express.js?
In docs, there is a section about notification signatures but I don't know how to combine it with Express.js
This question is a migrated from official Kentico Cloud Forum, that would be deleted.
In the API reference, there is a sample describing webhook validation in various languages including node.js.
If you want to use express.js you could start with this template code:
const express = require('express');
const crypto = require('crypto');
// Create a new instance of express
const app = express();
// Set up a raw bodyparser to read the webhook post
const bodyParserRaw = require('body-parser').raw({
type: '*/*',
});
function webhookValidator (req, res, next) {
// get the header signature from the webhook request
const givenSignature = req.headers['x-kc-signature'];
// throw error if it's missing
if (!givenSignature) {
console.log('Missing signature');
return res.status(409).json({
error: 'Missing signature'
});
}
// create HMAC from the raw request body
let hmac = crypto.createHmac('sha256', [your-webhook-secret-key]);
hmac.write(req.body);
hmac.end();
// get a base64 hash from HMAC
let hash = hmac.read().toString('base64');
// check validity with timingSafeEqual
let webhookValid = false;
try {
webhookValid = crypto.timingSafeEqual(Buffer.from(givenSignature, 'base64'), Buffer.from(hash, 'base64'));
} catch (e) {
webhookValid = false
}
// return validity
if (webhookValid) {
return next();
} else {
console.log('Invalid signature');
return res.status(409).json({
error: 'Invalid signature'
});
}
}
// create a route and pass through the bodyparser and validator
app.post('/webhook', bodyParserRaw, webhookValidator, ( req, res, next ) => {
// If execution gets here, the HMAC is valid
console.log('webhook is valid');
});
EDIT
You can use the Kontent webhook helper library to quickly verify the webhook notifications and their signatures. The library is available as #kentico/kontent-webhook-helper npm package and helps you avoid common problems when calculating the hash.

No logs after Passport.js authenticate middleware

I am trying to debug a failing JWT auth setup, which always returns a 401.
My passport setup (middleware/auth.js)
import passport from 'passport'
import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt'
module.exports = function() {
var options = {};
options.jwtFromRequest = ExtractJwt.fromAuthHeader()
options.secretOrKey = 'superdupersecret'
var strategy = new JwtStrategy(options, function(payload, done) {
console.log('this is not printing') <---------------
var user = payload.sub || null;
if (user) {
return done(null, { id: user._id });
} else {
return done(new Error("User not found"), null);
}
});
passport.use(strategy);
return {
initialize: () => {
console.log('this only prints on boot'); <---------------
return passport.initialize();
},
authenticate: () => {
console.log('this too') <---------------
return passport.authenticate("jwt", {session: false});
}
};
};
My server.js file where I initialize passport:
import express from 'express'
(...)
var auth = require("./middleware/auth.js")();
// Instantiate app
const app = express();
// Initialize passport for auth use
app.use(auth.initialize())
And my protected route that always returns a 401:
import express from 'express'
var auth = require("../middleware/auth.js")();
const userRouter = express.Router()
userRouter.get('/dashboard', auth.authenticate(), (req, res) => {
res.send('It worked! User id is: ' + req.user + '.')
})
export default userRouter
I have tried to add print statements within the actual passport.js module itself, as well as passport-jwt, with no success.
After the authentication middleware on the protected route, nothing logs.
I have tried a ton of setup permutations over the past 3 days now. Any help would be greatly appreciated
Ok, I followed the tutorial you mentioned and it seems to work.
Here are some notes (some may be obvious, no offense).
Copy exactly the code as the tutorial
After you have everything, you need to "login". Make a POST request to /token. Content type has to be application/json and on the body of the request you need to sent an object with email and password (from tutorial).
After you login, the server returns a token.
Take that token and now make a GET request to /user. In the headers of the request add: Authorization: JWT [your token here]. You have to write "JWT" and the token separated by one space.
The server returns a status 200. I modified so it returns the user.
app.get("/user", auth.authenticate(), function(req, res) {
res.json({user: req.user});
});

Categories