How to find a route in Express? - reactjs

I am using Express and trying to check login credentials, It works fine when i use post request without route. But I am getting error when i use express route.
This is my index.js code
const app = express();
app.use(bodyParser.json());
mongoose.connect("mongodb://localhost/bookworm", { useNewUrlParser: true });
console.log("post request");
app.use("api/auth", auth);
app.get("/*", (req, res) => {
res.sendFile(path.join(__dirname, "index.html"));
});
app.listen(8080, () => console.log("Running on localhost:8080"));
routes/auth.js code,
const router = express.Router();
router.post("/", (req, res) => {
res.status(400).json({ errors: { global: "Invalid Credentials" } });
});
I am expecting, 400:Invalid Credentials. but i am getting
"TypeError: Cannot read property 'global' of undefined"

It seems you're not letting your app know that it has to use router in certain endpoints.
import express from 'express'
const app = express()
const router = express.Router()
router.post('/', (req, res) => {
res.status(401).json({ errors: { global: "Invalid Credentials" } });
})
app.use('api', router)
app.listen(8080, () => console.log('listening on 8080'))
Now you can call the endpoint like so: http://localhost:8080/api with a POST request and it should return you a 401 error
More info here: https://expressjs.com/en/guide/routing.html#express-router

Related

AxiosError with Get Method give me 404 Error Page

When I request data from Mongoose, it shows me an error and tells me that the page does not exist, knowing that I tested the back-end in Postman and it succeeded. I also tested the react by fetching data from an external link and it succeeded. I do not know what the problem is?!
I try with this code
This is my back-end code
const app = require("./app");
const mongoose = require("mongoose");
app.set("port", process.env.PORT || 3000);
const mongoURI = "mongodb://localhost:27017/get-now";
mongoose.connect(mongoURI, {
    useNewUrlParser: true,
    useUnifiedTopology: true
})
.then(() => console.log(`database connected`))
.catch(err => console.log(err));
const port = process.env.PORT || 3000;
app.listen(port, () => {console.log(`the server is ${port}`)});
routes.get("/alldata" , async (req, res) => {
try {
const foodDatas = await Data.find({})
res.send(foodDatas);
console.log(foodDatas)
} catch (error){
res.status(500).json({
Error: error
})
}
});
This is my front-end (Reactjs) code
const fetchData = async () => {
    axios.get('http://localhost:3000/alldata')
  .then((res) => {
    console.log(res.data)
}).catch (err => {
console.log(err)
})
    }
  useEffect(() => {
    fetchData()
  }, [])
All these don't work it give me Error 404 page with data: undefined
did you configure the cors in the app file?
if don't, please install cors.
and add:
const cors = require('cors')
also:
app.use(
cors({
origin: "*",
})
);
Note:
Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources

React profile page, how to avoid 'GET http://localhost:3001/users/profile 401 (Unauthorized)' when trying to get JSON data from back end

For this application, I am using React & Express. I have React running on PORT 3000, and Express running on PORT 3001. On the Express side, I have authentication working that uses JWT.
First, here is my auth.js service file:
const jwt = require('jsonwebtoken');
const models = require('../models');
const bcrypt = require('bcryptjs');
var authService = {
signUser: function (user) {
const token = jwt.sign({
Username: user.Username,
UserId: user.UserId
},
'secretkey',
{
expiresIn: '1h'
}
);
return token;
},
verifyUser: function (token) {
try {
let decoded = jwt.verify(token, 'secretkey');
return models.users.findByPk(decoded.UserId);
} catch (err) {
console.log(err);
return null;
}
},
hashPassword: function (plainTextPassword) {
let salt = bcrypt.genSaltSync(10);
let hash = bcrypt.hashSync(plainTextPassword, salt);
return hash;
},
comparePasswords: function (plainTextPassword, hashedPassword) {
return bcrypt.compareSync(plainTextPassword, hashedPassword);
}
}
module.exports = authService;
When a user makes a POST request to the signup route, it works:
router.post('/signup', function (req, res, next) {
models.users.findOrCreate({
where: {
Username: req.body.username
},
defaults: {
FirstName: req.body.firstName,
LastName: req.body.lastName,
Email: req.body.email,
Password: authService.hashPassword(req.body.password)
}
})
.spread(function (result, created) {
if (created) {
res.redirect("http://localhost:3000/login");
} else {
res.send('This user already exist')
}
});
});
Signup works in both Postman and React.
When a user makes a POST request to the login route, it works:
router.post('/login', function (req, res, next) {
models.users.findOne({
where: {
Username: req.body.username
}
}).then(user => {
if (!user) {
console.log('User not found')
return res.status(401).json({
message: "Login Failed"
});
} else {
let passwordMatch = authService.comparePasswords(req.body.password, user.Password);
if (passwordMatch) {
let token = authService.signUser(user);
res.cookie('jwt', token);
res.redirect('http://localhost:3001/users/profile');
} else {
console.log('Wrong Password');
}
}
});
});
Login works in both Postman and React.
When a user makes a GET request to the profile route, it semi-works:
router.get('/profile', function (req, res, next) {
let token = req.cookies.jwt;
if (token) {
authService.verifyUser(token).then(user => {
if (user) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(user));
} else {
res.status(401);
res.send('Invalid authentication token');
}
});
} else {
res.status(401);
res.send('Invalid authentication token');
}
});
This works only in Postman, I can see the data that I want using Postman. In React, it will not get the profile route that I request. This is where the error comes in: Console Error
On the React side, this is profile GET component:
import React from 'react';
import axios from 'axios';
class UserProfile extends React.Component {
constructor(props) {
super(props);
this.state = {
profileData: []
}
};
fetchProfileData = () => {
var encodedURI = window.encodeURI(this.props.uri);
return axios.get(encodedURI).then(response => {
this.setState(() => {
return {
profileData: response.data
};
});
});
};
componentDidMount() {
this.fetchProfileData();
}
render() {
console.log(this.state.profileData);
if (this.state.profileData.length === 0) {
return <div>Failed to fetch data from server</div>
}
const profile = this.state.profileData.map(user => (
<div key={user.UserId}>Hello world</div>
));
return <div>{profile}</div>
}
}
export default UserProfile;
Then when I go to render this component, I just:
<UserProfile uri="http://localhost:3001/users/profile" />
Which then will render 'Failed to fetch data from server', then the console will log the '401 (Unauthorized)' error. I just can't get it to render in React.
And if anyone wants my Express app.js file for some extra information:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var models = require('./models');
var cors = require('cors');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(cors());
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
models.sequelize.sync().then(function () {
console.log("DB Synced Up");
});
module.exports = app;
Thank you in advanced. I have been struggling to figure this out.
I have tried toying with my UserProfile component. And I've tried toying with my /profile route in Express. The only 2 errors I've gotten is the 401 (Unauthorized) and something about the Headers. I know that my JWT key gets passed onto reacts side, because when I do 'localhost:3000/profile' (react side), I can see that I have the cookie stored. I'm not sure on how to approach authorization on React side. At this point, I am very clueless on what to do. This is the first time I've tried setting up authentication with React. I have always used Express and the .hbs files to render my profile pages. But I've been told that you shouldn't render a profile page in the back-end. So, here I am trying to do it with React.
I have rendered things from the back-end to the front-end, but that's without the use of JWT. I strongly believe that it has something to do with the JWT cookie. I just don't know how to authenticate it in React. Thanks again in advanced.
I fixed it by adding this into my React project:
I added this into my fetchProfileData()
{ withCredentials: true }
fetchProfileData = () => {
var encodedURI = window.encodeURI(this.props.uri);
return axios.get(encodedURI, { withCredentials: true }).then(response => {
this.setState(() => {
return {
profileData: response.data
};
});
});
};
Then in Express, I toyed with my Profile route. Put the data into an array, and sent it on its way:
router.get('/profile', function (req, res, next) {
var userData = [];
let token = req.cookies.jwt;
if (token) {
authService.verifyUser(token).then(user => {
userData.push(user);
res.send(userData);
});
} else {
res.status(401);
res.send('Invalid authentication token');
}
});

How do I get Axios to hit routes in monorepo?

I am using a monorepo-styled build and I am struggling to get routes to hit properly. I am clicking my button:
const handleSubmit = () => {
console.log("button clicked");
axios.get('/', {
params: {
username: "John1904",
}
})
.then((res) => {
console.log(res.data);
});
};
And I am getting the index.ts file, which makes sense. When I attempt to use '/users or /users/, it doesn't work. I get
>GET http://localhost:3000/users?username=John1904 404 (Not Found)
>Uncaught (in promise) AxiosError {message: 'Request failed with status code 404'
This is in the browser console, while nothing else shows in my terminal.
My index.ts that is handling routes is:
const app: Express = express();
const port = process.env.PORT;
app.use(helmet());
app.use(cors());
app.use(express.json());
app.use('/users', usersRouter);
app.use('/', (_req, res) => res.status(200).send('Service online'));
app.use(errorHandler);
app.use(notFoundHandler);
And my server/src/routes/users/router.ts file is:
const router = express.Router();
router.get('/', async (_req: Request, res: Response) => {
try {
const items = await UserService.findAll();
res.status(200).send(items);
} catch (e) {
res.status(500).send(unwrapRouterErrorMessage(e));
}
});
So why is my request not going into the app.use('/users', usersRouter);?
Okay, thanks for asking about the ports, because I checked the URL requests in the dev tools and it was all going through to the frontend and not hitting the backend. Everything was going to the port 3000 instead of 3006. For now I hardcoded the route to go to http://localhost:3006/ and it worked. Thanks again.

NextJs - React component methods get called twice per request

I'm experimenting with NextJs Custom Server using Express. And i noticed that on every request, getInitialProps gets called twice. When trying to find out what the problem is i stumbled upon React.Strictmode being the reason for that since it calls certain class methods and constructor twice to help debug. When setting it to false, the getInitialProps method gets called three times. NextJs "pages" folder routing is disabled.
To be mentioned that render() gets called twice or three times too.
My server.js :
require('dotenv').config();
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const mongoose = require('mongoose');
const app = next({ dev });
mongoose.connect(process.env.DB_URI)
.then(()=>{
console.log('>Succesfully connected to the database');
app.prepare()
.then(() => {
const server = express();
server.listen(3000, (req, res) =>{
console.log('>Listening on port 3000');
});
server.get('*', (req, res)=>{
app.render(req, res, '/index', {something:true});
})
})
.catch((ex) => {
console.error(ex.stack);
process.exit(1);
})
})
.catch(e=>{
console.log('<!>Error connecting to database: \n' + e);
});
and my GetInitialProps:
static async getInitialProps(ctx){
console.log({...ctx.query});
console.log('once');
return {props:{...ctx.query}};
}
Console when Strictmode on:
{ something: true }
once
{ something: true }
once
Console when Strictmode off:
{ something: true }
once
{ something: true }
once
{ something: true }
once

"Error: socket hang up" error displayed when using Postman with ReactJS and MongooseDB

I'm following a tutorial for setting up a React application with MongooseDB, Express etc. I'm using Postman for GET, POST. See code below (I've starred the password from the database string).
When I send GET HTTP://localhost:8001 it shows "hello world" which I expect.
When I send GET HTTP://localhost:8001/tinder/cards it hangs and eventually displays the error "Error: socket hang up".
When I send POST HTTP://localhost:8001/tinder/cards it hangs and eventually gives a 500 Internal Server error.
Can anyone point me in the direction of where to debug please? I'm guessing the connection works as when I send GET HTTP://localhost:8001 it shows "hello world".
Thanks again.
import express from 'express'
import mongoose from 'mongoose'
import Cards from './dbCards.js'
import Cors from 'cors'
// App Config
const app = express();
const port = process.env.PORT || 8001
const connection_url = `mongodb+srv://admin:*******#cluster0.iyemf.mongodb.net/tinder-db?retryWrites=true&w=majority`
// middlewares
app.use(express.json())
app.use(Cors())
// db config
mongoose.connect(connection_url, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology:true,
})
// api endpoints
app.get('/', (req, res) => res.status(200).send("hello world"));
app.post('/tinder/cards', (req, res) => {
const dbCard = req.body;
Cards.create(dbCard, (err, data) => {
if (err) {
res.status(500).send(err)
} else {
res.status(201).send(data)
}
})
})
app.get("/tinder/cards", (req, res) => {
Cards.find((err, data) => {
if (err) {
res.status(500).send(err)
} else {
res.status(200).send(data)
}
});
});
// listener
app.listen(port, () => console.log(`listening on localehost: ${port}`));
You should also add the urlencoded middleware:
app.use(express.json());
app.use(express.urlencoded({
extended: true,
}));

Resources