ExpressJS problem with rendering subdomain - javascript

I am writing store and i have a problem with rendering.
I want to have subdomain /category and it's working just find for route like tis
const CategoryOne = ((req, res) =>{
res.render('shop/category');
});
router.get('/category', CategoryOne);
This is working perfect, but when i go on subdomain category/shoes i want to be redirect on /category with parametr shoes
const Category = ((req, res) =>{
const categoryPass = req.params.category;
res.render('shop/category', {
category: categoryPass
});
});
router.get('/category/:category', Category);
and it's not working, should i redirect? When i do it
res.redirect('/category')
Then i dont have category parametr
EDIT:
What i have done so far:
const CategoryOne = ((req, res) =>{
const passedCategory = req.session.categorypassed;
req.session.categorypassed = undefined;
console.log(passedCategory);
Product.find((err, response) => {
res.render('shop/category', {
title: 'Test', products: response, category: passedCategory
});
});
});
const Category = ((req, res) =>{
req.session.categorypassed = req.params.category;
res.redirect('/category');
});
The problem is, when i refresh page i dont have this paramets, is there any way to save it?

A better way to handle this is to use a central public directory for your assets and request them with an absolute path, such as /assets/images/logo.png, instead of a relative path, such as assets/images/logo.png.
You can read more about relative and absolute paths here

Related

How to create a downloadable link in react and express

I have a react app in which I have a button. Basically a div.
This is returned from my Button Component and everything else are props.
<button className={"button "+styleButton} onClick={handleClick}>
{source && <img src={source} alt={alt} className={"image "+styleImage} /> }
<h3 className="text">{children}</h3>
</button>
Now what I did when someone clicks this Button(div) is :
const handleClick = () => {
console.log('downloading...');
let a = document.createElement('a');
a.href = '192.168.43.102/download/brief';
a.download = 'brief.pdf';
a.click();
}
On clicking on that div, I want a pdf to be downloaded on the client side. There are hundreds to ways on the internet. Some send a request with(axios) and download on front-end and then create a downloadable link and some just use an anchor tag.
I tried some of these but I can't make it working. Also on the express side.
This route is my express side:
const router = require('express').Router();
const { Router } = require('express');
const path = require('path');
const { route } = require('./api');
const brief = path.join(__dirname, '..', '/public/resources/krishi-brief.pdf');
const uml = path.join(__dirname, '..', '/public/resources/krishi-uml.pdf');
router.get('/brief', (req, res) => {
res.sendFile(brief);
});
router.get('/uml', (req, res) => {
res.download(uml);
});
router.get('/proposal', (req, res) => {
res.send("Not found");
});
router.get('/ppt', (req, res) => {
res.send("Not found");
});
module.exports = router;
I have a very good pfd which is non-corrupted but when I get the file, it is corrupted because none of the applications can open it.
I also tried:
router.get('/uml', (req, res) => {
res.set({
'Content-Type': 'application/pdf'
})
res.download(uml);
});
But now I am confused about the implementation and also if this is the right way.
Please tell me if this is the right(professional) way to do this in react app and where is it wrong? I am only getting corrupted file :(
OK so when I click on the download, the server 192.168.43.102 should be written as http://192.168.43.102 and the anchor tag won't give or throw and error but just download something which I am not sure about which is not even on your route.
Basic thing I was struggling on.

How to share/store data between routes in express (nodejs)?

I'll go in detail on what I really want my server to do.
So basically, I'm creating a project in which the user register and then logs in.
The routes are like - localhost:3000/login and localhost:3000/register
Now when the user logs in using their credentials (POST) , it should send them to localhost:3000/home which is unique for every person. I don't want to send the data like we do for templating engines but I want to make that data accessible across all routes so that I can use it whenever I like.
What I'm having trouble with is that when the person logs in , their data gets stored in a session (which contains their name and other user data) which as of now is not sharable between routes. The session gets stored for the /login route and I'm unable to use it for the /home route or for any other route for that matter.
Is there any way that I can use save a session every time a person logs in (using POST) and make that session data available across all my routes ?
server.js
var express = require('express');
const path = require('path');
const fs = require('fs');
const session = require('express-session');
const { v4: uuidv4 } = require('uuid');
const app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public/auth-pages')));
app.use(express.json());
var publicPath = __dirname+"/public"
var authPagesPath = publicPath+"/auth-pages"
var jsonPath = __dirname+"/json"
var usersFile = jsonPath+"/users.json"
var testVar = 1;
app.set('view engine', 'pug')
// have to be on top
app.use(logger)
app.get('/',(req,res) => {
res.sendFile('index.html',{root:publicPath})
})
app.get('/home',(req,res) => {
var data = {}
res.render('home',data)
})
app.get('/profile',(req,res) => {
var data = {}
res.render('profile',data)
})
app.get('/login',(req,res) => {
res.sendFile('login.html',{root:authPagesPath})
})
app.get('/register',(req,res) => {
res.sendFile('register.html',{root:authPagesPath})
})
app.post('/register',(req,res) => {
var data = req.body;
if (register(data)){
res.send({
register:"success"
})
}
else {
res.send({
register:"fail"
})
}
})
app.post('/login',(req,res) => {
var data = req.body;
fs.readFile(usersFile,(error,fullData) => {
var fullData = JSON.parse(fullData);
allUsernames = Object.keys(fullData);
if (!allUsernames.includes(data.username)){
res.send({
login:"fail",
reason:"invalid-username"
})
}
else if (fullData[data.username]['pwd'] != data.pwd){
res.send({
login:"fail",
reason:"wrong-pwd"
})
}
else {
res.send({
login:"success",
user:fullData[data.username]
})
// session storage
req.session.user = {
username:data.username,
id:fullData[data.username]['id']
}
console.log(req.session)
}
})
})
app.get('/test',(req,res) => {
testVar += 1;
res.send(""+testVar);
})
function register(data){
fs.readFile(usersFile,(err,fullData) => {
var fullData = JSON.parse(fullData)
if (Object.keys(fullData).includes(data.username)){
console.log('username taken')
}
else {
fullData[data.username] = {
id:uuidv4(),
pwd:data.pwd
}
fullData = JSON.stringify(fullData,null,4)
fs.writeFile(usersFile,fullData,error => {
})
}
})
return true;
}
You can use cookies to keep user data between routes.
If you dont want to store the whole data in the browser,
you can keep the user id in cookies and store the whole data in a repository object.
for example:
you can create a class that will store the state of the logged in users and can be reachable between routes.
the class should be instantiate and you should export its object.
( this solution keeps the state in memory and will be lost when service restarts/shutdown. to make the state available after restarts you can store the state in db (redis, mongo etc...)).
repo class:
class MyRepository {
constuctor() {
this.users = {};
}
set(user) {
this.users[user.id] = user;
}
get(userId) {
return this.users[userId];
}
}
let repo = new MyRepository();
module.exports = repo;
route:
const express = require('express');
const router = express.Router();
const repo = require('myrepository.js'); // this line will get you the object with all logged in users already
router.post('/login', (req, res, next) => {
// check if user logged in and get the user id (to myUserId);
user = ...
logged = ...
if (logged) {
res.cookie('userId', user.id)
repo.set(user)
}
});
route.get('/home', (req, res, next) => {
let userId = req.cookies.userId // get user id from cookie
let user = repo.get(userId);
});
You can do this by having some sort of a class that holds user's data. Please be aware that this solution is not scalable and you are designing a single point of failure.
For instance, if you have multiple servers running your application with a load balancer that routes requests to your servers. Let's say Server A creates an object from a class for User A. In the second or third request, presume that User A's request gets routed to Server B, which has not created an object that holds User A's data. This leads to scalability and even perhaps inconsistency issues.

Access express response data client side

In my express router I check if the data inserted on a form are valid then if they are I render another page passing form data. I would like to access the data I pass client-side. On the chat.ejs view I have a chatroom.js client file, I want to access the data there without having to access them in a script tag.
I thought about using Ajax but the only answer I found here on StackOverflow was marked as wrong, so how do I go about that?
router.js
module.exports=function(app) {
const express = require('express');
const router = express.Router();
const {check, validationResult} = require('express-validator');
const {matchedData} = require('express-validator/filter');
router.get('/', (req, res) => {
res.render('index', {
data: {},
errors: {}
})
});
router.post('/enter', [
check('username')
.isLength({min: 1})
.withMessage('Username is required').trim(),
check('room')//implement personalized check
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.render('index', {
data: req.body,
errors: errors.mapped()
})
}
else {
const data = matchedData(req);
return res.render('chat',{
user: data.username,
room:data.room
})
}
});
return router;
//MOVE TO SUPPORT
function find(name) {
return 1;
}
}
there is really nothing client-side so far so It seems useless just posting my views. Alternatively, I could use Ajax on client.ejs to handle the form submission but I would like to keep this clean and handle the routing with the router file.
I ended up creating two global variables in a script tag for my index.ejs page like this
<script>
var user = <%- JSON.stringify( user ) %>
var room = <%- JSON.stringify(room)%>;
</script>
and then I could access them in the chatroom.js file linked below

express + pug app, update multiple routes when txt file changes?

I have a simple express + app that consists of two views. localhost:xxxx/ and localhost:xxxx/view view simply displays a number read from a text file, the index route allows the user to increment that number, and also displays it. These two views will be displayed in different browser tabs, and I am using Pug templates. I have the index view updating fine, but cannot figure out how to update both views when the value in the text file changes.
Main router file
router.get('/', function(req, res) {
let data = fs.readFileSync('./data.txt', 'utf8');
let number = parseInt(data);
res.render('index', { number });
})
router.post('/', countController.increment);
router.get('/view', countController.readFile);
Controller
exports.increment = (req, res) => {
let data = fs.readFileSync('./data.txt', 'utf8');
let number = parseInt(data);
number++;
fs.writeFile('./data.txt', number, function() {
res.render('index', { number });
});
}
exports.readFile = (req, res) => {
let number = fs.readFileSync('./data.txt', 'utf8');
res.render('view', { number })
}
Is there a way to update both views that are running in separate browsers, or do i need to use something like socket.io? Thanks!
Thanks for the tip on websockets! This post led me in the direction to solve it, passing in socketio to my router. Use socket.io inside a express routes file

How do you get query params from the url in getInitialProps?

I have a clean url that contains some query param like this.
http://localhost:3000/post/:id
I'm trying to capture the query parameter 'id' on the client side like this.
static async getInitialProps({req, query: { id }}) {
return {
postId: id
}
}
render() {
const props = {
data: {
'id': this.props.postId // this query param is undefined
}
}
return (
<Custom {...props}>A component</Custom>
)
}
My express endpoint looks like this.
app.post(
'/post/:id',
(req, res, next) => {
let data = req.body;
console.log(data);
res.send('Ok');
}
);
But my server side console output ends up like this.
{ id: 'undefined' }
I've read the docs and the github issues but I can't seem to understand why this is happening.
Your frontend code is correct, fetching the post id from the query string is the way to go.
However your backend code is incorrect, first you need to use a GET route to render a Next.js page, and you must extract the path params to craft the final query params as a combination from both the regular query params as well as those path params, this could look like this using express:
const app = next({ dev: process.env.NODE_ENV === 'development' });
app.prepare().then(() => {
const server = express();
server.get('/post/:id', (req, res) => {
const queryParams = Object.assign({}, req.params, req.query);
// assuming /pages/posts is where your frontend code lives
app.render(req, res, '/posts', queryParams);
});
});
Check this Next.js example: https://github.com/zeit/next.js/tree/canary/examples/parameterized-routing for more info.

Categories

Resources