Need help Posting external API call to a local postgres database - sql

I'm working on a project that successfully displays the requested API call on a card in my HTML. I want to use a button click on that card to POST the same information to my local database of Favorites, then Get that Database to display on screen when called.
I've created the routes already that work in postman, just can link the external database to my local server.
//GameZ Backend Project
// document.getElementById('search').addEventListener('click', singleGame)
const express = require('express');
const app = express();
const { sequelize, Game, Favorites, Wishlist, User } = require('./models')
const bodyParser = require('body-parser');
const es6Renderer = require('express-es6-template-engine');
const fetch = require("node-fetch");
// const prohairesis =reqiure("prohairesis");
// const dotenv = require("dotenv");
//app.use('/', require('./routes/endpoints'));
const winston = require('winston');
const moment = require('moment');
const pg = require('pg-promise')();
const bcrypt = require('bcrypt');
const { response } = require('express');
//To convert the request to readable json format, we use bodyparser package
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false}))
app.engine('html', es6Renderer);
app.set('views', 'templates');
app.set('view engine', 'html');
app.use(express())
const logger = winston.createLogger({
level: 'info',
defaultMeta: { service: 'Game' },
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
]
})
// Middleware is the mediary that modifies information sent between the client and server
app.all('*', (req, res, next) => {
logger.info({
"Action": req.method,
"Path": req.path,
"Content_Type": req.header('Content-Type'),
"Body": req.body,
"Time": moment().format('MM/DD/YYYY, h:mm:ss a')
})
next()
})
app.get('/home', (req, res) => {
res.render('index2', {
locals: {
// name: '',
// games: []
}
});
})
//Get all games from gameInfo (app.get)
app.get('/gameInfo', async (req, res) => {
let gaming = await Game.findAll();
res.send(gaming)
console.log(gaming)
})
// Get a single game from the gameList (app.get)
// function singleGame(){
// let SGame = document.getElementById("singleGame").value
// let idArray = []
app.post('/home', async (req,res)=> {
const userInput = req.body.search;
const urlEncodedSearchString = encodeURIComponent(userInput);
let games = await fetch(`https://rawg.io/api/games?key=c1be38abe1e74ea3a7b554f19b8a9df6&search=${urlEncodedSearchString}`)
let gamesJson = await games.json()
let allGames = gamesJson.results.slice(0,8)
res.render('index3', {
locals: {
games: allGames,
name: ''
}
});
})
app.get('/home/2', async (req,res) => {
let gameCard = {}
//fetch using search by name
fetch(`https://rawg.io/api/games?key=c1be38abe1e74ea3a7b554f19b8a9df6&search=batman`)
.then((response) =>{
return response.json()
})
.then(data => {
console.log(data)
for (let index = 0; index < data.results.length; index++) {
gameCard = {
name: data.results[index].name,
id: data.results[index].id,
rating:data.results[index].rating,
released: data.results[index].released,
img: data.results[index].background_image
}
console.log(gameCard)
}
res.send(gameCard)
})
})
app.get('/oneresult/:gameslug' , async (req, res) => {
let faveCard = {}
console.log(req.params.gameslug, "IM HERE")
let games = await fetch(`https://rawg.io/api/games/${req.params.gameslug}?key=c1be38abe1e74ea3a7b554f19b8a9df6`)
console.log(games)
let gamesJson = await games.json()
console.log(gamesJson)
let allGames = gamesJson
console.log(allGames)
res.render('FavoritesWish', {
locals: {
game: allGames,
name: ''
}
});
} )
app.get('/gameList', async (req, res) => {
let gaming = await Game.findOne ({
where: {
}
})
if (gaming == null) {
res.statusCode = 400;
res.render('Not found');
} else {
res.statusCode = 200;
// res.send(gaming);
res.send('gaming', {
locals: {
gaming,
}
});
}
})
// }
// Add a game to the gameList
app.post('/gameInfo', async (req, res) => {
let createdUser = await Game.create(
{
gamename: req.body.gamename,
gameid: req.body.gameid,
star: req.body.star,
review: req.body.review,
username: req.body.username
}
)
res.statusCode = 200;
res.send(createdUser);
});
//Get all Favorites from Info (app.get)
// app.get('/favInfo', async (req, res) => {
// let favoritesgame = await Favorites.findAll();
// res.send(favoritesgame)
// })
// Get a single game from the favList (app.get)
app.get('/favList/:id', async (req, res) => {
let favoritesgame = await Favorites.findOne ({
where: {
id: req.params.id
}
})
if (favoritesgame == null) {
res.statusCode = 400;
res.render('Not found');
} else {
res.statusCode = 200;
// res.send(favoritesgame);
res.render('gaming', {
locals: {
favoritesgame,
}
});
}
})
// Add a game to the FavoritesList
app.post('/favInfo', async (req, res) => {
let createdFavorites = await Favorites.create(
{
gamename: req.body.gamename,
platform:req.body.platform,
gameid: req.body.gameid,
star: req.body.star,
releasedate: req.body.releasedate,
username: req.body.username
}
)
res.statusCode = 200;
res.send(createdFavorites);
});
//Get all Wishlist from Info (app.get)
app.get('/wishInfo', async (req, res) => {
let wishlistgame = await Wishlist.findAll();
res.send(wishlistgame)
})
// Get a single game from the WishList (app.get)
app.get('/wishList/:id', async (req, res) => {
let wishgame = await Wishlist.findOne ({
where: {
id: req.params.id
}
})
if (wishgame == null) {
res.statusCode = 400;
res.send('Not found');
} else {
res.statusCode = 200;
// res.send(wishlistgame);
res.render('wishlistgame', {
locals: {
wishgame,
}
});
}
})
// Add a game to the WishList
app.post('/wishInfo', async (req, res) => {
let createdwishList = await Wishlist.create(
{
gamename: req.body.gamename,
gameid: req.body.gameid,
rating: req.body.rating,
username: req.body.username
}
)
res.statusCode = 200;
res.send(createdwishList);
});
// Delete a game from the gameList
app.delete('/gameInfo/:gamename', async (req, res) => {
let deletedGames = await Game.destroy({
where: {
gamename: req.params.gamename
}
})
res.sendStatus(200).send(deletedGames);
})
// Delete a game from the Favorites
app.delete('/favInfo/:gamename', async (req, res) => {
let deletedGames = await Favorites.destroy({
where: {
gamename: req.params.gamename
}
})
res.sendStatus(200).send(deletedGames);
})
// Delete a game from the gameList
app.delete('/wishInfo/:gamename', async (req, res) => {
let deletedGames = await Wishlist.destroy({
where: {
gamename: req.params.gamename
}
})
res.sendStatus(200).send(deletedGames);
})
// Add a game to the gameList
app.post('/favInfo', async (req, res) => {
let createdUser = await Favorites.create(
{
gamename: req.body.gamename,
gameid: req.body.gameid,
star: req.body.star,
review: req.body.review,
username: req.body.username
}
)
res.statusCode = 200;
res.send(createdUser);
});
// app.post('/pushFav', async (req,res)=>{
// gameCard = {
// name: data.results[index].name,
// id: data.results[index].id,
// rating:data.results[index].rating,
// released: data.results[index].released,
// img: data.results[index].background_image
// }
// console.log(gameCard)
// }
// res.send(gameCard)
// });
//Update the meta for a game
app.patch('/gameInfo/:gamename', async (req, res) =>{
let gPatch = await Game.update(
{
gamename: req.body.gamename,
gameid: req.body.gameid,
star: req.body.star,
review: req.body.review,
username: req.body.username,
}, {
where:{
gamename: req.params.gamename
}
}
)
res.sendStatus(200).send(gPatch);
})
//Update the meta for a Favorites
app.patch('/favInfo/:gamename', async (req, res) =>{
let gPatch = await Favorites.update(
{
gamename: req.body.gamename,
gameid: req.body.gameid,
star: req.body.star,
review: req.body.review,
username: req.body.username,
}, {
where:{
gamename: req.params.gamename
}
}
)
res.sendStatus(200).send(gPatch);
})
//Update the meta for a Wishlist
app.patch('/wishInfo/:gamename', async (req, res) =>{
let gPatch = await Wishlist.update(
{
gamename: req.body.gamename,
gameid: req.body.gameid,
star: req.body.star,
review: req.body.review,
username: req.body.username,
}, {
where:{
gamename: req.params.gamename
}
}
)
res.sendStatus(200).send(gPatch);
})
// User login
app.post('/login', (req, res) => {
const { email, password } = req.body;
models.User.findOne({
where: { email: email }
}).then((user) => {
if (!user) {
res.json({ error: 'no user with that username' })
return;
}
bcrypt.compare(password, user.password, (err, match) => {
if (match) {
req.session.user = user;
res.json({ user_id: user.id, success: true })
} else {
res.json({ error: 'incorrect password' })
}
})
})
})
app.listen(8500, async ()=> {
console.log('Server is running on port 7500')
await sequelize.sync()
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Response Page</title>
</head>
<body>
<div class="flexbox">
<header class="header">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="./index2.html">Gamz+</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="./FavoritesWish.html">Favorites</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">Page 2</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">Page 3</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<!-- <li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">Something else here</a></li> -->
</ul>
</li>
<li class="nav-item">
<a class="nav-link disabled">Disabled</a>
</li>
</ul>
<form method="POST" action="/home" class="d-flex">
<input name="search" class="form-control me-2 search-button" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-sm btn-block btn-primary mt-auto" type="submit">Search</button>
</form>
</div>
</div>
</nav>
</header>
<div>
<div class="card" style="width: 18rem;">
<img src="${game.background_image}" class="card-img-top" alt="" width="100" height="120">
<div class="card-body">
<h5 id="title" class="card-title">${game.name} </h5>
<p class="card-text">Platform ${game.parent_platforms.map((platform)=>{
return platform.platform.name
})} </p>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">Rating ${game.rating}</li>
<li class="list-group-item">Game ID ${game.id}</li>
<li class="list-group-item">Release Date ${game.released}</li>
</ul>
<div class="card-body">
<a id="fav" href="#" class="card-link">Add to Favorites</a>
<a id="wish" href="#" class="card-link">Add to Wishlist</a>
<div class="input-group mb-3">
<button class="btn btn-outline-secondary" type="button" id="button-addon2">Add to Favorite</button>
</div>
</div>
</div>
</div>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="serverBP.js"></script>
</body>
</html>

Related

Conditional cookies expiration depends on "Remember me" box, (using passport.js)

I'm a new programmer :)
I'm trying to build an authentication system using passport.js.
Now, I want to determine the expiration of the cookies, depend on "Remember me" checkbox - For the example I chose: if “remember me” cookie expires after 2 minutes, otherwise cookie expires after 1 minute.
The problem is that it doesn't change the cookie's maxAge (it still 1 minute)
my code:
login.hbs
<body class="border border-2 border" style="margin-top: 15%; margin-right: 30%; margin-left: 30%">
<form action="/login" method="POST" class="form-signing container" style="max-width: 30rem">
<div class="text-center">
<!-- <img class="mb-4" src="public/images/wine4u_logo.jpeg" alt="" width="72" height="72"> -->
<h1 class="h3 mb-3 font-weight-normal">Login</h1>
<p>Please Enter your credentials in order to enter our store.</p>
</div>
<hr>
{{#if error}}
<div class="alert alert-danger">{{error}}</div>
{{/if}}
<div class="mb-3 text-left">
<label for="email" class="form-label"><b>Email</b></label>
<input type="email" placeholder="Enter Email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label"><b>Password</b></label>
<input type="password" placeholder="Enter Password" class="form-control" id="password" name="password" required>
</div>
<div class="checkbox mb-3 text-center">
<label>
<input type="checkbox" class="form-label" name="rememberMe" value="remember-me"> Remember me
</label>
<!-- <label for="checkbox"><b>Remember Me?</b></label> -->
<!-- <input type="checkbox" name="rememberMe"> -->
</div>
<div class="text-center">
<button type="submit" class="btn btn-lg btn-primary btn-block">Login</button>
</div>
</form>
<hr>
<form action="/register" class="text-center">
<button type="" class="btn btn-lg btn-secondary btn-block">Sign up page</button>
</form>
<!-- Register -->
</body>
app.js:
if (process.env.NODE_ENV !== "production") {
require("dotenv").config();
}
const express = require("express");
const path = require("path");
const bodyParser = require("body-parser");
const exphbs = require("express-handlebars");
const bcrypt = require("bcrypt");
const passport = require("passport");
const flash = require("express-flash");
const session = require("express-session");
const initializePassport = require("./public/javascript/passport-config");
const methodOverride = require("method-override");
initializePassport(
passport,
(email) => users.find((user) => user.email === email),
(id) => users.find((user) => user.id === id)
);
const app = express();
let users = [];
let cookieLength = 60 * 1000;
// handleBars middleware
app.engine(".hbs", exphbs.engine({ defaultLayout: "main", extname: ".hbs" }));
app.set("view engine", ".hbs");
app.use(bodyParser.json());
app.use(express.urlencoded({ extended: false }));
app.use(flash());
app.use(
session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
rolling: true,
cookie: { maxAge: cookieLength },
})
);
app.use(passport.initialize());
app.use(passport.session());
app.use(methodOverride("_method"));
app.get("/", checkAuthenticated, async (req, res) => {
res.render("index", { title: "Welcome to my site" });
});
app.get("/login", checkLoggedIn, async (req, res) => {
res.render("pages/login", {
title: "login page",
noHeader: true,
error: req.flash("error"),
csrf: "CSRF token goes here",
});
});
app.post(
"/login",
checkLoggedIn,
defineCookieLength,
passport.authenticate("local", {
successRedirect: "/",
failureRedirect: "/login",
failureFlash: true,
})
);
app.get("/register", checkLoggedIn, (req, res) => {
res.render("pages/register", { title: "register page", noHeader: true });
});
app.post("/register", async (req, res) => {
try {
const hashedPassword = await bcrypt.hash(req.body.password, 10);
users.push({
id: Date.now().toString(),
username: req.body.name,
email: req.body.email,
password: hashedPassword,
});
console.log("after:", users);
res.redirect("login");
} catch {
res.redirect("/register");
}
});
app.delete("/logout", function (req, res, next) {
req.logout(function (err) {
if (err) {
return next(err);
}
res.redirect("/login");
});
});
app.get("/about", checkAuthenticated, async (req, res) => {
// console.log("users in /login:", users)
res.render("pages/about", { title: "About us" });
});
function defineCookieLength(req, res, next) {
if (req.body.rememberMe === "on") {
req.session.cookie.maxAge = 120 * 1000;
next();
return;
}
next();
}
// validate that the user is already logged in before let him see other pages
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect("/login");
}
// validate that user can't use login/register pages if he is already logged in
function checkLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return res.redirect("/");
}
next();
}
const PORT = process.env.PORT || 8000;
app.listen(PORT, () => {
console.log(`Server Running on port: http://localhost:${PORT}`);
});
passport-config.js
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");
function initialize(passport, getUserByEmail, getUserById) {
const authenticateUser = async (email, password, done) => {
const user = getUserByEmail(email);
if (user == null) {
return done(null, false, { message: "No user with that email" });
}
try {
if (await bcrypt.compare(password, user.password)) {
return done(null, user);
} else {
return done(null, false, { message: "Password incorrect" });
}
} catch (err) {
return done(err);
}
};
passport.use(new LocalStrategy({ usernameField: "email" }, authenticateUser));
passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser((id, done) => {
return done(null, getUserById(id));
});
}
module.exports = initialize;

Express update/delete routes are not working but no errors either

I'm learning node express by making a to-do list. I'm having trouble with marking a to-do as complete/incomplete and deleting them. It's not giving me any errors so I'm trying to console log wherever I can.
The _id in the database is console logging so I think I have my variables correct? Please see below the server.js and main.js files for the comments where I think could be wrong.
I've been stuck on this problem for 3 days now...
EDIT: I just noticed findOneAndUpdate() is a mongoose function. I don't have mongoose yet... I think I'm on the right track...
server.js
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const MongoClient = require("mongodb").MongoClient;
const cors = require("cors");
const { request } = require("mongodb");
const PORT = process.env.PORT || 8000;
app.use(cors());
const username = "hidden";
const password = "hidden";
const connectionString = `mongodb+srv://${username}:${password}#cluster0.7k2ww.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`;
MongoClient.connect(connectionString, { useUnifiedTopology: true }).then(
(client) => {
console.log("Connected to database");
const db = client.db("to-do-list");
const toDoCollection = db.collection("to-dos");
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static("public"));
app.get("/", async (req, res) => {
const result = await toDoCollection.find().toArray();
const itemsLeft = await toDoCollection.countDocuments({
done: false,
});
res.render("index.ejs", { todos: result, left: itemsLeft });
});
app.post("/addtodo", (req, res) => {
toDoCollection
.insertOne({ todo: req.body.todo, done: false })
.then((result) => {
res.redirect("/");
})
.catch((error) => console.error(error));
});
app.put("/markComplete", async (req, res) => {
try {
await toDoCollection.findOneAndUpdate(
{
_id: req.body.todoId, // Is this line talking with my main.js file?
},
{
$set: { done: true },
},
{ sort: { _id: -1 }, upsert: false }
);
console.log(req.body.todoId);
res.json("Task completed");
} catch (err) {
console.log(err);
}
});
app.put("/markIncomplete", async (req, res) => {
try {
await toDoCollection.findOneAndUpdate(
{
_id: req.body.todoId,
},
{
$set: { done: false },
},
{ sort: { _id: -1 }, upsert: false }
);
console.log(req.body.todoId);
res.json("Task completed");
} catch (err) {
console.log(err);
}
});
app.delete("/deleteToDo", async (req, res) => {
console.log(req.body.todoId);
try {
await toDoCollection
.findOneAndDelete({ _id: req.body.todoId })
.then((result) => {
console.log("todo deleted");
res.json("todo deleted");
});
} catch {
console.log(err);
}
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
}
);
main.js
const deleteTask = document.querySelectorAll(".delete-todo");
const completeTask = document.querySelectorAll(".incomplete");
const incompleteTask = document.querySelectorAll(".complete");
Array.from(deleteTask).forEach((e) => {
e.addEventListener("click", deleteToDoFunc);
});
Array.from(completeTask).forEach((e) => {
e.addEventListener("click", completeToDoFunc);
});
Array.from(incompleteTask).forEach((e) => {
e.addEventListener("click", incompleteToDoFunc);
});
async function deleteToDoFunc() {
console.log("Delete working!");
const todoId = this.parentNode.dataset.id;
console.log(todoId);
try {
const res = await fetch("deleteToDo", {
method: "delete",
headers: { "Content-type": "application/json" },
body: JSON.stringify({
todoId: todoId,
}),
});
const data = await res.json();
console.log(data);
location.reload();
} catch (err) {
console.log(err);
}
}
async function completeToDoFunc() {
console.log("Update working!");
const todoId = this.parentNode.dataset.id;
console.log(todoId);
try {
const res = await fetch("markComplete", {
method: "put",
headers: { "Content-type": "application/json" },
body: JSON.stringify({
todoId: todoId, // Is this line talking with the server.js file?
}),
});
const data = await res.json();
console.log(data);
// location.reload();
} catch (err) {
console.log(err);
}
}
async function incompleteToDoFunc() {
console.log("Incomplete task");
const todoId = this.parentNode.dataset.id;
console.log(todoId);
try {
const res = await fetch("markIncomplete", {
method: "put",
headers: { "Content-type": "application/json" },
body: JSON.stringify({
todoId: todoId,
}),
});
const data = await res.json();
console.log(data);
location.reload();
} catch (err) {
console.log(err);
}
}
index.ejs
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="../css/font-awesome-4.7.0/css/font-awesome.min.css"
/>
<link rel="stylesheet" href="css/style.css" />
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:wght#300;400&display=swap"
rel="stylesheet"
/>
<title>To Do</title>
</head>
<body>
<div class="container">
<header class="flexContainer">
<h1 class="title main-font center">To Do List</h1>
</header>
<form class="center" action="/addtodo" method="POST">
<input type="text" placeholder="Add a To Do" name="todo" />
<button type="submit" class="submitButton">
<i class="fa fa-plus-square"></i>
</button>
</form>
<div class="to-do-list flexContainer">
<ul class="task-list center">
<% todos.forEach(todo => { %>
<li class="todo-name main-font complete-task" data-id="<%=todo._id%>"> <!-- The route should know which to-do to update/delete based on _id -->
<% if (todo.done === true) { %>
<span class="complete"><%= todo.todo %></span>
<% } else { %>
<span class="incomplete"><%= todo.todo %></span>
<% } %>
<span class="fa fa-trash delete-todo"></span>
</li>
<%}) %>
</ul>
</div>
<h2 class="main-font center">Left to do: <%= left %></h2>
</div>
<script type="text/javascript" src="/js/main.js"></script>
</body>
</html>
When you try to update your To-Do List, does it override everything in your document? I see that your using a PUT request instead of a PATCH request, and a PUT request would replace your all your data instead of updating a single field

VueJS MEVN stack - axios put 'Error: Request failed with status code 404' although Postman 'put' works fine

I'm following a tutorial to build a full stack app using VueJS and the MEVN stack. I have
a) built mongo db
b) build api back end with one mongoose model 'Student'
c) got the back end api running at localhost:4000/api
d) got the front end running with VueJS and Axios to read data from
the api
e) got READ, CREATE and DELETE working fine from my VueJS app
f) UPDATE is not working
g) Postman PUT is working fine though, so I know the back end is
fine.
Back end routes are
const express = require('express');
const studentRoute = express.Router();
// model
let StudentModel = require('../models/Student');
studentRoute.route('/create-student').post((req, res, next) => {
console.log('creating one student at /create-student')
StudentModel.create(req.body, (error, data) => {
if (error) {
return next(error)
} else {
console.log(`student created ${JSON.stringify(data)}`)
res.json(data)
}
})
});
studentRoute.route('/').get((req, res, next) => {
console.log('GET all students')
StudentModel.find((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
studentRoute.route('/edit-student/:id').get((req, res, next) => {
console.log('get one student at /edit-student/:id')
StudentModel.findById(req.params.id, (error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
// Update
studentRoute.route('/update-student/:id').post((req, res, next) => {
console.log(`attempting to update one student with id ${req.params.id}`)
console.log(`request body = `)
console.log(JSON.stringify(req.body))
console.log(req.body)
StudentModel.findByIdAndUpdate(req.params.id,
{ $set: req.body },
(error, data) => {
if (error) {
console.log(`an error has taken place`)
return next(error);
} else {
res.json(data)
console.log('Student successfully updated!')
}
})
})
// Delete
studentRoute.route('/delete-student/:id').delete((req, res, next) => {
console.log('delete one student at /delete-student/:id')
StudentModel.findByIdAndRemove(req.params.id, (error, data) => {
if (error) {
return next(error);
} else {
res.status(200).json({
msg: data
})
}
})
})
module.exports = studentRoute;
front end update code is
<template>
<div class="row justify-content-center">
<div class="col-md-6">
<h3 class="text-center">Update Student</h3>
<form #submit.prevent="handleUpdateForm">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" v-model="student.name" required>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" v-model="student.email" required>
</div>
<div class="form-group">
<label>Phone</label>
<input type="text" class="form-control" v-model="student.phone" required>
</div>
<div class="form-group">
<button class="btn btn-danger btn-block">Update</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts">
import { Vue } from 'vue-class-component';
import axios from "axios";
export default class EditComponent extends Vue {
student!: {
name: '',
email: '',
phone: ''
}
data() {
return {
student: { }
}
}
created() {
let apiURL = `http://localhost:4000/api/edit-student/${this.$route.params.id}`;
axios.get(apiURL).then((res) => {
this.student = res.data;
})
}
handleUpdateForm() {
let id = this.$route.params.id
let apiURL = `http://localhost:4000/api/update-student/${this.$route.params.id}`;
console.log(`attempt to update student at url`)
console.log(apiURL)
console.log(`with id`)
console.log(id)
console.log(`attempt to update student ${JSON.stringify(this.student)}`)
axios.put(apiURL, this.student)
.then(res => {
console.log(`response is ${res}`)
this.$router.push('/view')
})
.catch(error => {
console.log('error when updating student')
console.log(error)
});
}
}
</script>
when I use Postman I get this response from the api
attempting to update one student with id 6119d671cc9ce131207bd37c
request body =
{"_id":"6119d671cc9ce131207bd37c","name":"PHIL","email":"philanderson888#hotmail.com","phone":7888849991,"__v":0}{ _id: '6119d671cc9ce131207bd37c',
name: 'PHIL',
email: 'philanderson888#hotmail.com',
phone: 7888849991,
__v: 0 }
Student successfully updated!
when I use VueJS to update my Student I get the following error from this code
// Update
studentRoute.route('/update-student/:id').post((req, res, next) => {
console.log(`attempting to update one student with id ${req.params.id}`)
console.log(`request body = `)
console.log(JSON.stringify(req.body))
console.log(req.body)
StudentModel.findByIdAndUpdate(req.params.id,
{ $set: req.body },
(error, data) => {
if (error) {
console.log(`an error has taken place`)
return next(error);
} else {
res.json(data)
console.log('Student successfully updated!')
}
})
})
attempt to update student at url
EditComponent.vue?720f:29 http://localhost:4000/api/update-student/6119d671cc9ce131207bd37c
EditComponent.vue?720f:30 with id
EditComponent.vue?720f:31 6119d671cc9ce131207bd37c
EditComponent.vue?720f:32 attempt to update student {"_id":"6119d671cc9ce131207bd37c","name":"PHIL","email":"phil#phil.com","phone":123,"__v":0}
xhr.js?b50d:177 PUT http://localhost:4000/api/update-student/6119d671cc9ce131207bd37c 404 (Not Found)
dispatchXhrRequest # xhr.js?b50d:177
xhrAdapter # xhr.js?b50d:13
dispatchRequest # dispatchRequest.js?5270:52
Promise.then (async)
request # Axios.js?0a06:61
Axios.<computed> # Axios.js?0a06:87
wrap # bind.js?1d2b:9
handleUpdateForm # EditComponent.vue?720f:33
eval # EditComponent.vue?2308:5
eval # runtime-dom.esm-bundler.js?830f:1400
callWithErrorHandling # runtime-core.esm-bundler.js?5c40:6988
callWithAsyncErrorHandling # runtime-core.esm-bundler.js?5c40:6997
invoker # runtime-dom.esm-bundler.js?830f:347
EditComponent.vue?720f:39 error when updating student
EditComponent.vue?720f:40 Error: Request failed with status code 404
at createError (createError.js?2d83:16)
at settle (settle.js?467f:17)
at XMLHttpRequest.handleLoad (xhr.js?b50d:62)
I'm aware mongo has updated their methods for handling updates and have tried the following
1)
StudentModel.findByIdAndUpdate(req.params.id,
{ $set: req.body },
(error, data) => {
StudentModel.findOneAndUpdate({_id:req.params.id},
{ $set: req.body },
(error, data) => {
StudentModel.updateOne({_id:req.params.id},
{ $set: req.body },
(error, data) => {
In each case I am getting the error above and in each case Postman works fine. So there's a problem with the URL being formed and I'm not sure what it is???
Your help would be appreciated!
Thank you
Philip
Also, just in case it is relevant, here is the back end app.js
let express = require('express'),
cors = require('cors'),
mongoose = require('mongoose'),
database = require('./database'),
bodyParser = require('body-parser');
// Connect mongoDB
mongoose.Promise = global.Promise;
//mongoose.set('useFindAndModify',false);
mongoose.connect(database.db, {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log("Database connected")
},
error => {
console.log("Database could't be connected to: " + error)
}
)
const studentAPI = require('../api/routes/student.route')
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cors());
// API
app.use('/api', studentAPI)
// Create port
const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
console.log('Connected to port ' + port)
})
const logUsage = (logCode) => {
console.log(`http serving with code ${logCode}`)
}
app.use((req, res, next) => {
console.log(`logging data in 'next'`)
next(logUsage(200));
});
app.use(function (err, req, res, next) {
console.log('in app.use')
console.error(err.message);
if (!err.statusCode) err.statusCode = 500;
res.status(err.statusCode).send(err.message);
});
You can try to replace post in update route with put

Can not get the latest data after updated the user profile(vue.js 2, vuex, laravel 8)

I'm a newbie in VueX. I face a problem which is after I updated the profile information and save it successfully, the database has shown the latest updated info but the user interfaces cannot retrieve the latest data. The state seems no updated.
My profile UI
https://i.stack.imgur.com/8QtI9.png
but after updated, all the info disappear and didn't show the latest info
https://i.stack.imgur.com/ul1ob.png
UserProfile.vue
<template>
<div class="container" style="padding-top:25px">
<div class="main-font">My Profile</div>
<div class="d-flex row">
<div class="col-6">
<ValidationObserver v-slot="{ handleSubmit }">
<form #submit.prevent="handleSubmit(updateProfile)">
<div class="d-flex py-4">
<div>
<img class="profile" src="/img/default.png" alt=""
</div>
<div class="my-auto ml-5">
<button type="submit" class="btn upload text"><i class="fas fa-upload fa-sm pr-2"></i>Upload new picture</button>
</div>
</div>
<div class="form-group col-10 p-0 m-0">
<ValidationProvider name="Name" rules="required|alpha" v-slot="{ errors }">
<label class="text">Name</label>
<input type="text" id="name" class="form-control form-text" placeholder="Enter your username" v-model="userForm.name">
<span class="error-messsage">{{ errors[0] }}</span>
</ValidationProvider>
<!-- <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small> -->
</div>
<div class="form-group col-10 p-0 m-0 mt-4">
<ValidationProvider name="E-mail" rules="required|email" v-slot="{ errors }">
<label class="text">Email</label>
<input type="email" id="email" class="form-control form-text" placeholder="Enter email" v-model="userForm.email">
<span class="error-messsage">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<button type="submit" class="btn col-10 p-o save-but">SAVE CHANGES</button>
</form>
</ValidationObserver>
</div>
<div class="w-50">
<img class="bg-img" src="/img/profile-bg.png" alt="">
</div>
</div>
</div>
script
<script>
import { ValidationProvider, ValidationObserver, extend } from 'vee-validate/dist/vee-validate.full';
export default {
components: {
ValidationProvider,
ValidationObserver,
},
data() {
return {
userForm: {
name: '',
email: '',
},
error: null,
}
},
created () {
this.userForm = JSON.parse(JSON.stringify(this.$store.getters.currentUser));
},
computed: {
currentUser(){
return this.$store.getters.currentUser;
},
},
methods: {
getUser (){
const token = this.$store.getters.currentUser.token
axios.get('/api/auth/userprofile',{
headers: {
Authorization: `Bearer ${token}`
}
})
.then(response => {
this.userForm= response.data.user;
})
},
updateProfile () {
const token = this.$store.getters.currentUser.token
// console.log(this.$store.getters.currentUser.token)
axios.put('/api/auth/update-profile',
{
name: this.userForm.name,
email: this.userForm.email,
},
{
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json" // add content-type
}
})
.then(response => {
this.userForm.name = response.data.name;
this.userForm.email = response.data.email;
swal({
icon: "success",
text: "Update Succesfully!",
});
// this.$store.commit('update');
})
}
}
}
</script>
store.js
import {getLoggedinUser} from './auth';
import {getUser} from './auth';
const user = getLoggedinUser();
const updateUser = getUser();
export default {
state: {
currentUser: user,
isLoggedin: !!user,
loading: false,
auth_error: null,
reg_error:null,
registeredUser: null,
update: null,
},
getters: {
isLoading(state){
return state.loading;
},
isLoggedin(state){
return state.isLoggedin;
},
currentUser(state){
return state.currentUser;
},
authError(state){
return state.auth_error;
},
regError(state){
return state.reg_error;
},
registeredUser(state){
return state.registeredUser;
},
update(state){
return state.update;
}
},
mutations: {
login(state){
state.loading = true;
state.auth_error = null;
},
loginSuccess(state, payload){
state.auth_error = null;
state.isLoggedin = true;
state.loading = false;
state.currentUser = Object.assign({}, payload.user , {token: payload.access_token});
localStorage.setItem("user", JSON.stringify(state.currentUser));
},
loginFailed(state, payload){
state.loading = false;
state.auth_error = payload.error;
},
logout(state){
localStorage.removeItem("user");
state.isLoggedin = false;
state.currentUser = null;
},
registerSuccess(state, payload){
state.reg_error = null;
state.registeredUser = payload.user;
},
registerFailed(state, payload){
state.reg_error = payload.error;
},
update(state, payload) {
state.currentUser = payload.data;
}
},
actions: {
login(context){
context.commit("login");
},
// update(context){
// // state.currentUser.update(context);
// }
}
};
auth.js
export function registerUser(credentials){
return new Promise((res,rej)=>{
axios.post('/api/auth/register', credentials)
.then(response => {
res(response.data);
})
.catch(err => {
rej('An error occured.. try again later.')
})
})
}
export function login(credentials){
return new Promise((res,rej)=>{
axios.post('/api/auth/login', credentials)
.then(response => {
setAuthorization(response.data.access_token);
res(response.data);
})
.catch(err => {
rej('Wrong Email/Password combination.')
})
})
}
export function getLoggedinUser(){
const userStr = localStorage.getItem('user');
if(!userStr){
return null
}
return JSON.parse(userStr);
}
export function getUser(credentials){
return new Promise((res,rej)=>{
axios.get('/api/auth/userprofile', credentials)
.then(response => {
// setAuthorization(response.data.access_token);
res(response.data);
})
.catch(err => {
rej('No User')
})
})
}
Please help me if you have any ideas or solution.
You're not running any dispatches of your store.
You have defined update mutation, but commented it.
Uncomment this
// this.$store.commit('update')
and modify it like so:
this.$store.commit('update', { data: response.data })
Next do the same for your login request.

Formatting authentication request object from VueJS properly

I have a VueJS/Vuex frontend consuming an express/postgres api.
In Postman, both registration and login work with a request like:
{ "user": { "email": "user#gmail", "password":...}}
From the Vue app, registration works as expected, but for login, instead of sending a request object like
{ "user": { "email": "user#gmail", "password":...}}
, which is what the api is expecting, it is sending only,
{ "email": "user#gmail", "password":...}
This results in the api throwing:
TypeError: Cannot read property 'email' of undefined
Here is my Login component:
<template>
<div class="ui stackable three column centered grid container">
<div class="column">
<h2 class="ui dividing header">Log In</h2>
<Notification
:message="notification.message"
:type="notification.type"
v-if="notification.message"
/>
<form class="ui form" #submit.prevent="login">
<div class="field">
<label>Email</label>
<input type="email" name="email" v-model="email" placeholder="Email" required>
</div>
<div class="field">
<label>Password</label>
<input type="password" name="password" v-model="password" placeholder="Password" required>
</div>
<button class="fluid ui primary button">LOG IN</button>
<div class="ui hidden divider"></div>
</form>
<div class="ui divider"></div>
<div class="ui column grid">
<div class="center aligned column">
<p>
Don't have an account? <router-link to="/signup">Sign Up</router-link>
</p>
</div>
</div>
</div>
</div>
</template>
<script>
import Notification from '#/components/Notification'
export default {
name: 'LogIn',
components: {
Notification
},
data () {
return {
email: '',
password: '',
notification: {
message: '',
type: ''
}
}
},
// beforeRouteEnter (to, from, next) {
// const token = localStorage.getItem('tweetr-token')
// return token ? next('/') : next()
// },
methods: {
login () {
this.$store
.dispatch('login', {
email: this.email,
password: this.password
})
.then(() => {
console.log(this.$store.user)
// redirect to user home
this.$router.push('/')
})
.catch(error => console.log(error))
}
}
}
</script>
And this is my store.js:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
// import SubscriptionsService from './services/SubscriptionsService'
Vue.use(Vuex)
const VUE_APP_ROOT_API = 'http://localhost:8000'
export default new Vuex.Store({
state: {
status: '',
user: JSON.parse(localStorage.getItem('user'))
},
mutations: {
auth_request (state) {
state.status = 'Signing in...'
},
set_user (state, user) {
state.user = user
localStorage.setItem('user', JSON.stringify(user))
console.log(user)
},
auth_success (state) {
state.status = 'success'
},
auth_error (state) {
state.status = 'Invalid credentials'
},
logout (state) {
state.status = ''
state.user = null
localStorage.removeItem('user')
}
},
actions: {
register ({ commit }, user) {
return new Promise((resolve, reject) => {
commit('auth_request')
console.log(process.env.VUE_APP_ROOT_API)
axios({ url: VUE_APP_ROOT_API + '/api/auth', data: user, method: 'POST' })
.then(async resp => {
const user = resp.data.user
commit('auth_success')
commit('set_user', user)
resolve(resp)
})
.catch(err => {
commit('auth_error', err)
localStorage.removeItem('token')
reject(err)
})
})
},
login ({ commit }, user) {
return new Promise((resolve, reject) => {
commit('auth_request')
console.log(user);
axios({ url: VUE_APP_ROOT_API + '/api/auth/login', data: user, method: 'POST' })
.then(resp => {
const user = resp.data.user
// console.log(user)
// console.log(resp)
commit('auth_success')
commit('set_user', user)
resolve(resp)
})
.catch(err => {
commit('auth_error')
commit('logout')
reject(err)
})
})
},
logout ({ commit }) {
return new Promise((resolve) => {
commit('logout')
localStorage.removeItem('token')
delete axios.defaults.headers.common['authorization']
resolve()
})
}
},
getters: {
isAuthenticated: state => !!state.user,
authStatus: state => state.status,
user: state => state.user
}
})
for comparison, here is my working SignUp component:
<template>
<div class="ui stackable three column centered grid container">
<div class="column">
<h2 class="ui dividing header">Sign Up, it's free!</h2>
<form class="ui form" #submit.prevent="signup">
<div class="field">
<label>Username</label>
<input type="username" name="username" v-model="username" placeholder="Username">
</div>
<div class="field">
<label>Email</label>
<input type="email" name="email" v-model="email" placeholder="Email">
</div>
<div class="field" >
<label>Password</label>
<input type="password" name="password" v-model="password" placeholder="Password">
</div>
<button class="fluid ui primary button">SIGN UP</button>
<div class="ui hidden divider"></div>
</form>
<div class="ui divider"></div>
<div class="ui column grid">
<div class="center aligned column">
<p>
Got an account? <router-link to="/login">Log In</router-link>
</p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'SignUp',
data () {
return {
email: '',
password: '',
username: '',
notification: {
message: '',
type: ''
}
}
},
methods: {
signup: function () {
let data = {
user: {
email: this.email,
password: this.password,
username: this.username
}
}
this.$store.dispatch('register', data)
.then(() => this.$router.push('/'))
.catch(err => console.log(err))
},
}
}
</script>
How do I format the request object to match what the api expects?
Try sending the payload in a similar structure you have for your sign up function:
.dispatch('login', {
user: {
email: this.email,
password: this.password
}
})