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

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."

Related

Axios 404 when requesting from routes folder

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}`)
})

I have a problem validating on update (express)

I'm trying to create a validator that will display an error message when a user tries to update a column that doesn't exist in the database schema. I'm using PostgreSQL. When I send a request with the correct allowed updates it returns an error: 'Invalid updates' What am I missing?
const updateQuestion = async (req, res) => {
const updates = Object.keys(req.body)
const allowedUpdates = ['title', 'text, questionCateg']
const isValidOperation = updates.every((update) => allowedUpdates.includes(update))
if (!isValidOperation) {
return res.status(400).send({
error: 'Invalid updates'
})
}
try {
const {
id
} = req.params;
const {
title,
text,
questionCateg
} = req.body
const updateQuestion = await pool.query("UPDATE Questions SET title = $1, text = $2, questionCateg = $3 WHERE id =$4",
[title, text, questionCateg, id]);
console.log(updateQuestion)
res.json('Question updated')
} catch (e) {
res.status(400).send()
}
}
Route:
router.patch('/questions/:id', updateQuestion)
Thanks in advance!
What do you see when you console.log(req.body) ? you should concentrate on that updates array.
You can use body-parser in your app.js or express.json() middleware
This way you can succesfully receive your items that you are sending to your backend.
You can send the updates in post request body with the key updates. Then you can parse it like req.body.updates (updates is an array)
You can use body parser like this
app.use(bodyParser.urlencoded({
extended: true
}));
or app.use(express.json())
you can see further information in this post express.json() and express.urlencoded()

Stripe succesfully creating customer without card details

Complete web/Stripe newbie here. I built an iOS app, but the method of taking payments that I wanted to use isn't allowed on iOS, so I had to set up a website for it.
The website uses HTML/CSS, with a node backend hosted on Heroku. The website is a simple site that takes the name and card details of the user, but there's currently an issue with my implementation.
In app.get(), I create a customer and a setupIntent, and then this gets filled out when the user clicks a button on the site (just an event listener in js on the client-side).
My issue is, when I create a customer it creates an empty customer every time the page is loaded. If I remove this customer, there is no extra customer being added on load, and the correct customer is created, but there is no card attached to the customer's account!
I'm sure this is a basic error on my part, as I rushed through learning web dev in order to get the app to accept payments (we got an unexpected rejection from the App Review team, basically saying our app will never be acccepted as long as it takes card details on the app).
Thanks in advance for any/all help.
Cheers!
Josh
Server-side:
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
require('dotenv').config()
const app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static("public"));
const Stripe = require('stripe');
const stripe = Stripe(process.env.SECRET_KEY);
app.get('/', async (req, res) => {
var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
const customer = await stripe.customers.create({
email: fullUrl.split('=')[1] //This gets the email sent in the URL from the app
});
const intent = await stripe.setupIntents.create({
customer: customer.id,
payment_method_types: ['card'],
});
console.log(fullUrl)
console.log(fullUrl.split('=')[1])
res.render('index', { client_secret: intent.client_secret });
})
app.listen(process.env.PORT || 3000);
Client-side:
var stripe = Stripe('livePublicKeyIsHere');
// const firebase = require("firebase");
// require("firebase/firestore");
var elements = stripe.elements();
var cardElement = elements.create('card');
cardElement.mount('#card-element');
var db = firebase.firestore();
var cardholderName = document.getElementById('cardholder-name');
var setupForm = document.getElementById('setup-form');
var clientSecret = setupForm.dataset.secret;
const queryString = window.location.search;
const email = queryString.split('=')[1];
setupForm.addEventListener('submit', function(ev) {
ev.preventDefault();
stripe.confirmCardSetup(
clientSecret, {
payment_method: {
card: cardElement,
billing_details: {
name: cardholderName.value
},
},
}
).then(function(result) {
if (result.error) {
console.log("Error!!!" + result.error.message);
window.alert("There's an error: " + result.error.message);
} else {
console.log("Success!!!");
window.alert("Account created! Download and log into the app in order to continue.");
addUserToFirestore(email)
}
});
});
function addUserToFirestore(email) {
createUserOnFirestore(email);
db.collection("Users").doc(email).collection("Settings").doc("info").set({
cardDetailsAdded: true
})
.then(() => {
console.log("Document successfully written!");
})
.catch((error) => {
console.error("Error writing document: ", error);
});
}
function createUserOnFirestore(email) {
db.collection("Users").doc(email).set({
exists: true
})
.then(() => {
console.log("Document successfully written!");
})
.catch((error) => {
console.error("Error writing document: ", error);
});
}
The reason is because you're using get instead of post. When your user clicks the button, it should fire a POST request to your server to generate a SetupIntent object which you have already done. You also should store a relation mapping between your user and the Customer that is created, so you don't always create a new Customer when user adds a new card, instead you add the new card to existing Customer object.
While using a customer is recommended, ultimately it is optional to provide a customer (API ref). You can also attach a payment method to a customer separately, as long as you do so before using it for a payment.
Note that unless attached to a customer, a payment method is one-time-use only.

How can I email links work on the front end?

I have built some functionality into my API that sends a verification email to a user and then when a get request is made to the route the user then becomes active and can be used to login. In order to make this work on the front end I have used a res.redirect which takes me to the login page.
The problem, however, is that this means that when I want to replicate this journey in postman I then receive a load of html rather than a formatted json response. So my question is, is there a way that we can handle this request so that, depending on where it is called, a different response is sent back? As I do not think an event listener will work in the case of an email.
For context, my application uses nodejs, mongodb and pug templates.
`exports.signup = catchAsync(async (req, res, next) => {
const { token } = req.params;
const { email } = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findOne({ email });
if (!user || !((await user.signUpId) === token)) {
return next(new AppError('Invalid link', 401));
}
user.ready = true;
user.singUpId = undefined;
await user.save({ validateBeforeSave: false });
const url = `${req.protocol}://${req.get('host')}/me`;
await new Email(user, url).sendWelcome();
await res.redirect('http://localhost:5000/login');
});`

Apple-pay with Stripe not recognized in Dashboard

I seem to have gotten backend index.js file working with an apple-pay payment request on the back-end. However the results do not show up in my Stripe dashboard. Spinning my wheels and cannot figure out why. Any help would be much appreciated.
Below is the code I am using on the back-end. When I press the pay button in Apple-Pay in the App, my terminal window shows "Payment requested" and "Success" messages.
I would then expect the USD amount to process in my stripe dashboard but I am gettin $0.00 and no activity. Any help would be wonderful!
// Add packages we need
const express = require('express')
const bodyParser = require('body-parser')
var stripe = require('stripe')('YOUR-SECRET-KEY')
// Create an express app
const app = express()
// Use body parser so we can parse the body of requests
app.use(bodyParser.json())
// Just a sanity check endpoint we can hit in the browser
app.get('/', function (req, res) {
res.send('This is the backend server for Metatoll Application!')
})
app.post('/pay', function (req, res) {
console.log('Payment requested')
var token = req.body.stripeToken
var amount = req.body.amount
var description = req.body.description
stripe.charges.create({
amount: amount,
currency: "usd",
description: description,
source: token,
}, function(err, charge) {
if (err !== null) {
console.log('error capturing')
console.log(err)
res.status(400).send('error')
} else {
console.log('success')
res.status(200).send('success')
}
});
})
app.listen(3000, () => {
console.log('Metatoll listening on port 3000')
})

Categories