I am writing a nodejs backend application for an application I developed with Vue. I need to create sessions for users' db operations and select databases according to the user. I wanted to use express-session for this, but the sessions I created are seen as undefined in different requests. How can I overcome this problem? I use history mode on Vue so my requests must go through the router for now. Also I can convey that I am open to alternative suggestions.
const express = require('express')
const app = express()
const productRequest = require("./controllers/products/products")
const customerRequest = require("./controllers/customers/customers")
const orderRequest = require("./controllers/orders/orders")
const controllerRequest = require("./controllers/controllers")
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
var session = require('express-session')
const cors = require("cors")
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
app.use(express.json());
app.use(cors());
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
app.use('/products', productRequest)
app.use('/orders', orderRequest)
app.use('/customers', customerRequest)
app.use('/controllers', controllerRequest)
module.exports = app;
const express = require('express');
const controllers = express.Router();
const login = require('./login.js')
const userkey = require("./userkey");
controllers.post("/login", (req, res, next) => {
login(req.body, response => {
if (response[0].total == 0) {
res.status(204).json({
message: "Fail",
result: null
})
} else if (response[0].total == 1) {
/* SESSION SETTED HERE */
req.session.corp = response[0].corp
console.log(req.session.corp)
/* HERE SEEMS CREATED */
res.status(200).json({
message: "Connected",
result: response
})
}
})
});
controllers.post("/userkey", (req, res, next) => {
/* CANT USE HERE response UNDEFINED*/
console.log(req.session.corp)
userkey([req.body, req.session.corp], response => {
res.status(200).json({
data: response
})
})
});
module.exports = controllers;
I had some massive headaches with sessions and would have kept going until I read
Also I can convey that I am open to alternative suggestions.
Please then consider using JWT
as simple as this :
var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
The jsonwebtoken package is simple to use and should match your needs.
Related
I am new to express and currently having issues connecting to an api
below is my code
const express = require("express");
const session = require("express-session");
const MongoStore = require("connect-mongo");
const flash = require("connect-flash");
const fetch = require("node-fetch");
const axios = require("axios");
const app = express();
const dotenv = require("dotenv");
dotenv.config();
let sessionOptions = session({
secret: "Javascript is so cool",
store: MongoStore.create({ mongoUrl: process.env.CONNECTIONSTRING }),
resave: false,
saveUninitialized: false,
cookie: { maxAge: 1000 * 60 * 60 * 24, httpOnly: true },
});
app.use(sessionOptions);
app.use(flash());
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.use(express.static("public"));
app.set("views", "views");
app.set("view engine", "ejs");
const router = require("./router");
const apiRouter = require("./apiRouter");
const options = {
url: "https://rms.pythonanywhere.com/api",
method: "",
json: {},
};
app.use("/", router);
app.use(options.url, apiRouter);
module.exports = app;
Below is the file i created for routes that goes to the api
const express = require("express");
const apiRouter = express.Router();
const request = require("request");
const fetch = require("node-fetch");
const userController = require("./controllers/userController");
const pageController = require("./controllers/pageController");
apiRouter.post("/user/create", async function (req, res) {
const api_url = "https://rms.pythonanywhere.com/api";
const fetch_res = await fetch(api_url, options);
const json = await fetch_res.json();
res.json(json);
});
module.exports = apiRouter;
When i submit my registration form i want it to send it post request to the url of the api and recieve its response. But whenever i send a post request to the api url it returns an error of (can't send post request to /user/create)
What i really want to achieve is to connect to this api link (rms.pythonanywhere.com/api) and be able to direct my routes for registration and login with some other routes to the api. I've been battling with this for over a week now. Please guys help me out, I'm new to express
Thanks in advance guys
I think your express app is unable to find the apiRouter so, you need to use express router first with the help of express.use() method.
You can add below line to your code.
express.use("/", apiRouter);
Thanks guys for your response. Although none was actually the solution, but it gave me a clue of what i needed to do.
What i used in solving my issues was axios. i required("axios") after installing from npm store and den i used it in my apiRouter.post("/user/create") route. Below is what i did to solve the issue
apiRouter.post("/register", async function (req, res) {
const api_url = "https://rms.pythonanywhere.com/api";
axios.post(api_url + "/user/create/", {
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: req.body.password,
user_type: req.body.user_type,
username: req.body.username,
}). then((response) =>{}).catch((error){})
});
I was able to send the data's from my post request made in apiRouter.post(/register) and recieved the success response in my then() and error response in my catch() block.
I have this GET request that fetches data from a third party api. I want to check if there is new data every 5-10 minutes or so. Right now i have this setup on my backend.
exports.get_alerts = async (req, res) => {
const alertsUrl = `https://www.g2smart.com/g2smart/api/alert?cpo=${req.params.cpo}&status=Opened&limit=10&page=1`;
const axios = require("axios");
const auth = await refreshToken;
const currTime = moment().subtract(1, "days").format("X");
const newAlertsData = [];
const availableUsers = await axios.get(
"http://localhost:5000/api/schedule/available"
) ....
and on the front end i have this code to send a get request to my alerts api endpoint.
getAlerts = async () => {
axios
.get("/api/alerts/total_fr_hpc")
.then((response) => console.log(response.data))
.catch((err) => console.log(err));
};
timer = (time) => {
const date = new Date(time);
return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
};
componentDidMount() {
this.alertsInterval = setInterval(this.getAlerts, 900000);
}
componentWillUnmount() {
clearInterval(this.alertsInterval);
My question is can i have all this done on the backend only? I read a bit about websockets but that seems to be only for a continuous 2way connection between the backend and frontend.
I'd like to have something like that towards my third party apis on the node/express server, either fetching data at a set interval or a continuous connection checking for new data without having to make GET requests from my frontend. I want to be able to get new Data and store it into MongoDB even when there is nobody logged in to the client side.
I want that the data the users get is always up to date without having at least one person logged in to trigger the GET requests.
This is how my node/express server is currently setup
const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const passport = require("passport");
const cors = require("cors");
const path = require("path");
const indexRouter = require("./routes/index");
const apiRouter = require("./routes/api"); //Import routes for "api" area of site
const app = express();
// CORS Middleware
app.use(cors());
app.options("*", cors());
// Bodyparser middleware
app.use(
bodyParser.urlencoded({
extended: false,
})
);
app.use(bodyParser.json());
// DB Config
const db = require("./config/keys").mongoURI;
// Connect to MongoDB
mongoose
.connect(db, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then(() => console.log("MongoDB successfully connected"))
.catch((err) => console.log(err));
// Passport middleware
app.use(passport.initialize());
// Passport config
require("./config/passport")(passport);
// Routes
// Add api routes to middleware chain.
app.use("/", indexRouter);
app.use("/api", apiRouter);
// Serve static assets (build folder) if in production
if (process.env.NODE_ENV === "production") {
// Set static folder
app.use(express.static("client/build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
}
const port = process.env.PORT || 5000;
app.listen(port, "0.0.0.0", () =>
console.log(`Server up and running on port ${port} !`)
);
I am not familiar with the axios as I always use the native fetch API. Maybe the isomorphic fetch can help.
I am using a NextJS/MERN stack. My NextJS is using my server.js file, along with importing the routes for my API. The routes appear to be working as they do show activity when firing an API call from Postman or the browser. However, this is where the activity stops. It's not getting passed the Model.find() function as far as I can tell. I am not sure if this has to do with Next js and the prepare method in the server.js, or if this is related to the bodyparser issue.
Here is my server.js
const express = require("express");
const urlObject = require('./baseURL')
const passport = require("./nextexpress/config/passport-setup");
const passportSetup = require("./nextexpress/config/passport-setup");
const session = require("express-session");
const authRoutes = require("./nextexpress/routes/auth-routes");
const KBRoutes = require("./nextexpress/routes/kb-routes");
const userRoutes = require('./nextexpress/routes/user-routes')
const pollRoutes = require('./nextexpress/routes/poll-routes')
const mongoose = require("mongoose");
const cookieParser = require("cookie-parser"); // parse cookie header
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const nextapp = next({ dev })
const handle = nextapp.getRequestHandler()
const bodyParser = require('body-parser');
// mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/kb', { useNewUrlParser: true });
mongoose.connect('mongodb://localhost:27017/kb')
console.log(process.env.MONGODB_URI)
const connection = mongoose.connection;
const baseURL = urlObject.baseURL
const PORT = process.env.PORT || 3000
connection.once('open', function () {
console.log("MongoDB database connection established successfully");
})
nextapp.prepare().then(() => {
const app = express();
console.log(process.env.PORT, '----port here ----')
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use("/api/auth", authRoutes);
app.use("/api/kb", KBRoutes);
app.use('/api/user', userRoutes)
app.use('/api/poll', pollRoutes)
app.get('/posts/:id', (req, res) => {
return nextapp.render(req, res, '/article', { id: req.params.id })
})
app.get('/redirect/:id', (req, res) => {
return nextapp.render(req, res, '/redirect')
})
app.all('*', (req, res) => {
return handle(req, res)
})
app.listen(PORT, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${PORT}`)
})
})
// connect react to nodejs express server
And the relevant route:
KBRoutes.get('/', (req, res) => {
console.log(KB.Model)
KB.find({}, (err, photos) => {
res.json(kbs)
})
})
I am able to get to each one of the routes. Before this was working, when I had the NextJS React portion split into a separate domain therefore separate server.js files. Once I introduced NextJs thats when this problem arose. Any help would be greatly appreciated.
It looks like the relevant route is trying to return json(kbs), but kbs doesn't seem to be defined. Returning the result of your find query would make more sense to me, including a nice error catcher and some status for good practice. Catching errors should tell you what's going wrong, i would expect an error in your console anyway that would help us out finding the answer even more.
KB.find({}, (err, photos) => {
if (err) res.status(401).send(err)
res.status(200).json(photos)
})
I'm trying to set a cookie with a post method in order to do some db query and put it back in the cookie value, as well as returning a json with the user data.
It works, the cookie is set and I get the json on http://localhost:8080
but I get a message from the compiler:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
How can I fix it so it won’t make this error?
my file structure is:
root/ app.js
root/controllers/ cookie.controller.js
root/routes/ cookie.route.js
app.js
const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const app = express();
const port = process.env.PORT || process.argv[2] || 8080;
app.use(cookieParser());
app.use(require('./routes/cookies'));
app.use(cors());
app.listen(port, () => console.log('cookie-parser demo is up on port: ' + port));
cookie.route.js
const express = require('express');
const cookieController = require('../controllers/cookies');
const router = express.Router();
router.use(require('cookie-parser')());
router.post('/', router.use(cookieController.getCookie));
module.exports = router;
cookie.controller.js
exports.getCookie = (req, res, next) => {
let auth = req.cookies.auth;
//...db queries, get userData
let userData = {
id: '123',
token: 'sfsdfs34',
email: 'user#gmail.com'
};
// if cookie doesn't exist, create it
if (!auth) {
res.status(200)
.cookie('auth', userData.id)
.json({ message: 'it works!', user: userData });
req.cookies.auth = userData.id;
}
next();
};
You're modifying the request cookie headers after sending the response at the end of your getCookie controller. You should remove req.cookies.auth = userData.id, and use res.cookie() instead before sending the response.
const express = require('express')
const cookieParser = require('cookie-parser')
const app = express()
app.use(cookieParser())
app.get('/', (req, res) => {
if (!req.cookies.auth) {
res.cookie('auth', { id: '123' })
}
res.json({ message: 'It worked!' })
})
app.listen(8080, () => console.log('http://localhost:8080))
Problem was solved after deleting the cors from app.js
I am using socket.io with express and using express session and express-socket.io-session, but I can't can't access properties of the express session in the socket.io session object and vice versa.
const server = require("http").createServer(app);
const client = require("socket.io").listen(server);
session = require("express-session")({
secret: "my-secret",
resave: true,
saveUninitialized: true
}),
sharedsession = require("express-socket.io-session");
app.use(session);
client.use(sharedsession(session, {
autoSave:true
}));
client.on("connection", (socket) => {
socket.on("input", data => {
console.log(socket.handshake.session.user)
socket.handshake.session.name = "bar"
socket.handshake.session.save()
})
})
app.post("/signup", (req, res, next) => {
req.session.user = "foo";
})
app.get("/test", (req, res, next) => {
console.log(req.session.name)
})
Both console.log() return undefined, as it seems like they both are two different objects.
I got my issue resolved, but can't seem to understand this weird issue when using var socket = io('http://localhost:8080') in the client HTML sock.io session id is differing from express session id, but when I do var socket = io() they both share the same session, and everything is working as expected.