fetch POST request is pending (sending data from registration form) - express

I know that similar questions have already been here, but I didn't find anything for my problem.
I am creating project using [Webpack-Express-Pug-VanillaJS] stack of technologies.
I'm trying to make POST-request to send formData to '/api/users' using fetch a push data to array in my express file, but its only pending...
What kind of problems it can be?
client-side code
document.addEventListener('DOMContentLoaded', () => {
async function postData(url, data) {
try {
console.log('addEventListener works!')
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
console.log('fetch works!')
return await response.json()
} catch(e) {
console.warn('Error',e.message)
}
}
const forms = document.getElementsByTagName('FORM');
for (let i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(e) {
console.log(forms[i])
e.preventDefault();
let formData = new FormData(this);
formData = Object.fromEntries(formData);
console.log(formData) return object like {name:'Zhanna', age:25, email:'123zhanna#gmail.com'}
postData('/api/users', formData).then(data => console.log('Successful!'))
})
}
})
server-side
const path = require('path')
const express =require('express')
const webpack = require('webpack')
const bodyParser = require('body-parser')
const users = require('../routes/userInfo')
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import config from '../../webpack.dev.config.js'
import { v4 } from 'uuid';
const PORT = process.env.PORT || 8080
const app = express(),
compiler = webpack(config)
app.use(users.router);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.json());
app.set('views', path.join(__dirname, "views"));
app.set('view engine', 'pug');
app.locals.basedir = __dirname;
app.use('/assets',express.static(path.join(__dirname,'assets')))
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
})
)
app.use(webpackHotMiddleware(compiler))
app.get('/registration', (req,res)=> {
res.status(200).render('registration')
})
app.get('/login', (req,res)=> {
res.status(200).render('signIn')
})
app.get('/', (req, res) => {
res.status(200).render('index')
}
)
app.get('/api/users', (req,res)=> {
res.status(200).json(users.list)
})
app.post('/api/users', (req,res)=> {
const user = {...req.body, id:v4()}
users.list.push(user)
console.log('Data was sent')
res.status(201).json(user)
})
app.listen(PORT, () => {
console.log(`App listening to ${PORT}....`)
console.log('Press Ctrl+C to quit.')
})
And in my console there is only 3 logs:
addEvent listener works!
<form class="registration--form" id="send-form">...<form>
3.{name: "Zhanna", surname: "Kaymedenova", gender: "female", brth: "07.01.1994", email: "zh.kaymed#gmail.com"}

Related

Vue 3, Socket IO - not listening to event

For server side I have following code:
const path = require("path");
const http = require("http");
const express = require("express");
const {instrument} = require('#socket.io/admin-ui')
const app = express()
const server = http.createServer(app)
const io = require("socket.io")(server, {
cors: {
origin: ["https://admin.socket.io", "http://localhost:3001"],
credentials: true
},
});
instrument(io, { auth: false });
server.listen(3000, () =>
console.log('connected')
)
io.on('connection', socket => {
console.log("user connected");
socket.on("join", function (room) {
console.log(room);
socket.join(room);
});
socket.on('newOrder', function (data) {
socket.emit('this', data)
console.log(data);
})
socket.on("thisNew", function (data) {
console.log('this new');
});
socket.on('disconnect', () => {
console.log('user disconnected');
});
})
and in the Vue (client side) I have following:
import VueSocketIO from 'vue-3-socket.io'
import SocketIO from 'socket.io-client'
export const useSocketIO = () => {
const socket = new VueSocketIO({
debug: true,
connection: SocketIO('http://localhost:3000')
})
return {
socket,
}
}
And in the component:
<script setup>
import { useSocketIO } from "#/services/socketio"
const { socket } = useSocketIO()
onMounted(async () =>
{
await socket.io.emit('join', 'servant')
socket.io.on('this', () =>
{
console.log('event this fired')
})
})
</script>
Event this is emitted from the server, but nothing is happening on the client side. What am I doing wrong here?

Heroku to netlify session wont store session values

This works fine when I am running it on Localhost3000(client) and localhost:3005(server). However once I publish my app to Heroku(server) and netlify(client) it for some reason tells me the req.session.steamuser when accessing /user is null even after it has been set in /api/auth/steam/return and I have tested that the req.session.steamuser=req.user accutally work.
Server.js
var express = require('express');
var passport = require('passport');
var session = require('express-session');
var passportSteam = require('passport-steam');
const cors = require("cors");
var SteamStrategy = passportSteam.Strategy;
var app = express();
const corsOptions = {
origin: ["https://stunning-bavarois-0eef55.netlify.app"],
credentials: true, //access-control-allow-credentials:true
methods: ["GET", "POST"],
};
app.use(cors(corsOptions));
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
passport.use(new SteamStrategy({
returnURL: 'https://temtestt.herokuapp.com/api/auth/steam/return',
realm: 'https://temtestt.herokuapp.com/',
apiKey: 'MY SECRET API KEY'
}, function (identifier, profile, done) {
process.nextTick(function () {
profile.identifier = identifier;
return done(null, profile);
});
}
));
app.use(session({
secret: 'db5910cc8b9dcec166fda1d2c34860b6f8cd932cea641ea39924ed18fe6fc863',
resave: true,
saveUninitialized: true,
cookie: {
SameSite:"none",
maxAge: 3600000,
secure:true
}
}))
// Initiate Strategy
app.use(passport.initialize());
app.use(passport.session());
app.get('/', (req, res) => {
res.status(200);
res.send("Welcome to root URL of Server");
});
app.get("/user", (req, res) => {
if (req.session.steamuser) {
res.status(200).send(req.session.steamuser)
}
else {
res.send(false)
}
})
app.get('/api/auth/steam', passport.authenticate('steam', { failureRedirect: '/' }), function (req, res) {
res.redirect('/')
});
app.get('/api/auth/steam/return', passport.authenticate('steam', { failureRedirect: '/' }), function (req, res) {
req.session.steamuser = req.user;
res.redirect('https://stunning-bavarois-0eef55.netlify.app/')
});
app.listen(process.env.PORT || 3005);
Client
import { useEffect, useState } from 'react';
import './App.css';
import axios from 'axios';
function App() {
const [user,setUser]=useState(null);
useEffect(()=>{
async function getUser(){
const data = await axios.get("https://temtestt.herokuapp.com/user",{withCredentials:true});
setUser(data.data);
}
getUser();
},[]);
return (
<div className="App">
<h1>Hello</h1>
{(user===false||user===null)?<><p>Please log in</p>Login</>:<p>{user.displayName}</p>}
</div>
);
}
export default App;
As mentioned already it works fine when I do with localhost and returns correct values. But when I try with netlify and heroku it almost seems like it doesn't recognize the session key or something.

API req always undefined from axios POST

I had using the middleware but still getting undefined from req. I'm using axios POST method on my client side. Here is my code.
app.ts:
import express from 'express';
import mongoose from 'mongoose';
import cors from 'cors';
import dotenv from 'dotenv';
import userAuth from './routes/userAuth';
const app = express();
dotenv.config();
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
app.use(express.json());
app.use(cors());
app.use('/userAuth', userAuth);
const CONNECTION_URL = process.env.MONGO_CONNECTION_URL!;
const PORT = process.env.PORT || 4000;
mongoose
.connect(CONNECTION_URL)
.then(() => {
app.listen(PORT, () =>
console.log(`Server is running on port ${PORT}`),
);
})
.catch((error) => {
console.log(error);
});
./route/userAuth.ts:
import { Router } from 'express';
import { register } from '../controllers/userAuth';
const router = Router();
router.post('/register', register);
export default router;
../controllers/userAuth:
import mongoose from 'mongoose';
import { Router as router, ErrorRequestHandler } from 'express';
import UserAuth from '../models/userAuthScema';
import jwt from 'jsonwebtoken';
import bcrypt from 'bcrypt';
export const register: ErrorRequestHandler = async ({ req, res }) => {
console.log(req);
if (!req) {
res.json({ message: `Req Undefined.` });
return;
}
let { userType, email, fName, lName, confirmPassword } = req.body;
let { password } = req.body;
const takenEmail = await UserAuth.findOne({ email });
const passwordValidationFailed = password !== confirmPassword;
if (takenEmail) res.json({ message: `User email has already been used.` });
else if (passwordValidationFailed)
res.json({ message: `Fail password validation.` });
else {
password = await bcrypt.hash(password, 10);
const dbUser = new UserAuth({
userType,
email,
firstName: fName,
lastName: lName,
password,
});
dbUser.save();
res.json({ message: `Success!` });
}
return;
};
CLient Post :
export const registerAccount = (newAccount: RegisterConfigs) => {
const baseURL = `http://localhost:4000`;
const apiURL = `${baseURL}/userAuth/register`;
const { userType, email, fName, lName, password, confirmPassword } =
newAccount;
const body = {
userType: userType === UserType.employee ? 'Employee' : 'Employer',
email: email.text,
firstName: fName.text,
lastName: lName.text,
password: password.text,
confirmPassword: confirmPassword.text,
};
console.log(JSON.stringify(body));
axios
.post(apiURL, JSON.stringify(body), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods':
'GET, POST, OPTIONS, PUT, PATCH, DELETE',
'Access-Control-Allow-Headers':
'x-access-token, Origin, X-Requested-With, Content-Type, Accept',
},
})
.then((response: any) => {
console.log(response);
})
.catch((error: any) => {
console.log(error.toJSON());
});
};
As you saw in my code, i'm using the express.urlencoded({ extended: true });, express.static('public');, express.json()); middleware. I'm not sure where is the problem, I tried to make the header's content-type to application/json also but still got this problem.
ref:
Ref1
Ref2
The solution, as suggested by derpirscher in this comment was to remove {} to get async (req, res ) => ... .

using passportjs passport.authenticate() in Sapper route or sapper middleware

I used passportjs in the past with expressjs and currently I'm trying to incorporate it with Sapper app but I'm unable to figure out how to inlcude the passport.authenticate() in my route because it's a sapper route not an express route. Also if I try to run everything in my server.js file I run into the issue of how to integrate it with the sapper middleware.
How do you use passport.authenticate() in/with Sapper middleware or sapper routes js files (which is the front not server routes)?
My server.js is typical:
const sirv = require('sirv');
import express from 'express';
var cookieParser = require('cookie-parser');
import * as sapper from '#sapper/server';
const session = require('express-session');
var passport = require('passport');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/passport', {
useNewUrlParser: true });
const MongoStore = require('connect-mongo')(session);
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
store: new MongoStore({ url: 'mongodb://localhost/passport' }),
cookie: { secure: false, maxAge: 1000 * 60 * 60 * 24 * 7 }
}));
app.use(passport.initialize());
app.use(passport.session());
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';
const assets = sirv('static', {
maxAge: 31536000, // 1Y
immutable: true
});
app.use(assets, sapper.middleware({
session: req => ({
user: req.session && req.session.user
})})).listen(process.env.PORT, err => { if (err) console.log('error', err); });
As you can see, Sapper is just a middleware so if I want to authenticate a user and send it to the front/sapper, I need to figure out how to run passport.authenticate() inside the middleware function, right?
If I want to use passport in the route JS file which is sapper front route:
//How to import passport.js here to make passport.authenticate() middleware available?
import passport from './passport';
import User from './mongoso';
export async function post(req, res, next) {
res.setHeader('Content-Type', 'application/json');
/* Retrieve the data */
var data = req.body;
req.session.user = data.email;
console.log("Here's the posted data:", data);
console.log("information in the session is:", req.session);
/* Returns the result */
return res.end(JSON.stringify({ Email: req.session.user }));
//return res.json({ data: data });
}
Any ideas? Greatly appreciated if someone out there could help.
You don't need to run passport.authenticate() inside the sapper.middleware. You need to add passport-local strategy firstly, then do serializeUser and deserializeUser, then create routes to do passport.authenticate and
after that catch req.session.passport object in sapper.middleware. I don't use passport-local strategy, but here is my working server.js with passport-github strategy.
//server.js
import sirv from 'sirv';
import express from 'express';
import passport from 'passport';
import { Strategy } from 'passport-github';
import bodyParser from 'body-parser';
import session from 'express-session';
import sessionFileStore from 'session-file-store';
import compression from 'compression';
import * as sapper from '#sapper/server';
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';
const FileStore = sessionFileStore(session);
passport.use(new Strategy({
clientID: 'someClientID',
clientSecret: 'someClientSecret',
callbackURL: 'http://localhost:3000/auth/callback',
}, (accessToken, refreshToken, profile, cb) => {
// console.log('success');
return cb(null, profile);
}));
passport.serializeUser(function (user, cb) {
cb(null, user);
});
passport.deserializeUser(function (obj, cb) {
cb(null, obj);
});
const expressServer = express()
.use(passport.initialize())
.use(bodyParser.json())
.use(session({
secret: 'conduit',
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 31536000
},
store: new FileStore({
path: `.sessions`
})
}))
.get('/auth/login',
passport.authenticate('github'))
.get('/auth/callback',
passport.authenticate('github', { failureRedirect: '/auth/login' }),
(req, res) => {
res.redirect('/');
//console.log(req.user.username);
})
.get('/auth/logout', (req, res) => {
req.logout();
req.session.destroy( function (err) {
res.redirect('/');
});
})
.use(
compression({ threshold: 0 }),
sirv('static', { dev }),
sapper.middleware({
session: req => {
const user = req.session.passport ? req.session.passport.user.username : null;
// console.log(req.session.passport.user.username);
return { user };
}
})
)
if (dev) {
expressServer.listen(PORT, err => {
if (err) console.log('error', err);
});
}
export { expressServer }
Аfter this, you can catch that this { user } object in your client
sapper route component through Stores using const { session } = stores(); console.log($session) or you can get it via special preload function to apply before page is rendered, like this for example in index.svelte
<script context="module">
export function preload(page, { user }) {
return { user };
}
</script>
<script>
import { stores } from "#sapper/app";
import { onMount } from "svelte";
const { session } = stores();
export let user;
onMount(() => {
console.log($session);
});
</script>
<div>
{#if !user}
<p>Not logged in</p>
{:else}
<p>Logged in!</p>
{/if}
</div>
Here i use two approaches same time, but most of time it will be enough to
use preload, no need to direct access to session in stores.
Hope this will help you. Good luck!
I used the answer from DioXine to implement Google Auth.
The cookie is now also http only.
import sirv from "sirv";
import express from "express";
import bodyParser from "body-parser";
import session from "express-session";
import sessionFileStore from "session-file-store";
import compression from "compression";
import * as sapper from "#sapper/server";
import passport from "passport";
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === "development";
passport.use(
new GoogleStrategy(
{
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/callback",
},
function (accessToken, refreshToken, profile, cb) {
// User.findOrCreate({ googleId: profile.id }, function (err, user) {
// return cb(err, user);
// });
return cb(null, profile);
}
)
);
passport.serializeUser(function (user, cb) {
cb(null, user);
});
passport.deserializeUser(function (obj, cb) {
cb(null, obj);
});
const FileStore = sessionFileStore(session);
const sessionConfig = {
secret: "sefmvks4Fgblolf4sdJHBd",
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
maxAge: 31536000,
},
//TODO: redis
store: new FileStore({
path: `.sessions`,
}),
};
express()
.use(passport.initialize())
.use(bodyParser.json())
.use(session(sessionConfig))
.get("/auth/google", passport.authenticate("google", { scope: ["profile"] }))
.get(
"/auth/google/callback",
passport.authenticate("google", { failureRedirect: "/auth/login" }),
(req, res) => {
res.redirect("/");
}
)
.get("/auth/logout", (req, res) => {
req.logout();
req.session.destroy(function (err) {
res.redirect("/");
});
})
.use(
compression({ threshold: 0 }),
sirv("static", { dev }),
sapper.middleware({
session: (req) => {
const user = req.session.passport ? req.session.passport.user.id : null;
return { user };
},
})
)
.listen(PORT, (err) => {
if (err) console.log("error", err);
});
This is not changed:
<script context="module">
export function preload(page, { user }) {
return { user };
}
</script>
<script>
import { stores } from "#sapper/app";
import { onMount } from "svelte";
const { session } = stores();
export let user;
onMount(() => {
console.log($session);
});
</script>
<div>
{#if !user}
<p>Not logged in</p>
{:else}
<p>Logged in!</p>
{/if}
</div>
If it only works after refresh check this:
https://github.com/sveltejs/sapper/issues/567#issuecomment-542788270

nuxtjs - global shared editable server variables

I'm using nuxtjs and I use app authentication against a restful API. I want to store in a server side variable my token, wich I use everywhere to request informations to the API, but I cannot store it in process.env variabls because I need to modify it when it expires (after 1 hour). The token is for the app, not for users, so every call to the api have to use the same token. I try to use fs to save my token in a json file and refresh it when it expires, but I cannot use fs in nuxtjs, it tells me that fs doesn't exists, maybe because I try to use it in client side.
Do you know how can I do that?
Thank you
I solved by using express in server side envirenment, I had to put server middleware configuration in nuxt.config.js:
const bodyParser = require('body-parser')
const session = require('express-session')
module.exports = {
...
serverMiddleware: [
bodyParser.json(),
session({
secret: 'my-secret',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 3600000 }
}),
'~/server'
],
...
and on /server/index.js file :
const express = require('express')
const api = require('./api')
// Create express router
const router = express.Router()
// Transform req & res to have the same API as express
// So we can use res.status() & res.json()
var app = express()
router.use((req, res, next) => {
Object.setPrototypeOf(req, app.request)
Object.setPrototypeOf(res, app.response)
req.res = res
res.req = req
next()
})
router.get('/myroute', (req, res) => {
api.get('myroute')
.then((data) => {
res.json({success: true})
})
.catch((e) => {
res.status(500).json({ message: 'An error occurred' })
})
})
module.exports = {
path: '/server',
handler: router
}
and on my /server/api.js file
const parameters = require('./parameters.js')
const router = require('./router.js')
const axios = require('axios')
const auth = {
accessToken: null,
expiresAt: null
}
const getToken = () => {
const expiresAt = auth.expiresAt
const accessToken = auth.accessToken
const expires = expiresAt ? (new Date()).getTime() : null
if (expires && expires - expiresAt > 0) {
return new Promise((resolve, reject) => {
resolve(accessToken)
})
}
return new Promise((resolve, reject) => {
axios.get(parameters.api + router.token, {
params: parameters.auth
})
.then(({data}) => {
auth.accessToken = data.access_token
auth.expiresAt = (new Date()).getTime() + data.expires_in - 60
resolve(data.access_token)
})
.catch((e) => {
reject(e)
})
})
}
const getCompleteRoute = (route) => {
return new Promise((resolve, reject) => {
getToken()
.then((token) => {
resolve(parameters.api + router[route] + '?access_token=' + token)
})
.catch((e) => {
reject(e)
})
})
}
const get = (route, params) => {
return new Promise((resolve, reject) => {
getCompleteRoute(route)
.then((completeRoute) => {
axios.get(completeRoute, {params: params})
.then(({data}) => {
resolve(data)
})
.catch((e) => {
reject(e)
})
})
.catch((e) => {
reject(e)
})
})
}
const post = (route, params) => {
return new Promise((resolve, reject) => {
getCompleteRoute(route)
.then((completeRoute) => {
axios.post(completeRoute, params)
.then(({data}) => {
resolve(data)
})
.catch((e) => {
reject(e)
})
})
.catch((e) => {
reject(e)
})
})
}
module.exports = {
get: get,
post: post
}