nodejs middleware typescript generic question - node.js

interface CustomRequest<T> extends Request {
user?: IUser,
body: T
}
interface CreateBody {
email:string;
}
interface deleteBody {
id:string;
}
router.post('/create', authenticate, (req:CustomRequest<CreateBody>, res) => {
Content.Create({
email:req.body.email
})
}
router.post('/delete', authenticate, (req:CustomRequest<deleteBody>, res) => {
Content.Create({
id:req.body.id
})
}
export const authenticate = async (
req: CustomRequest<null>
res: Response,
next: NextFunction,
) => {
try {
const user = await User.findToken(req.cookies.auth);
if (!user) return res.send({ success: false });
req.user = user;
next();
} catch (err) {
return res.send({ success: false });
}
};
I want to specify the request type by situation when designating middleware in nodejs.
req:CustomRequest
I've tried generics this way, but it doesn't work.
How can I define the type gracefully?
I would like to specify the type that some api have an e-mail in body and some api have a password in it.

Related

Correct Async/Await usage with Axios

I'm working with axios to post user responses to a database. I'm using this set up shown below to handle many posts back to back. I'm wanting to make sure that this is the correct set up to avoid backing up requests.
Is this the correct way to use async and await when using Axios?
// Frontend React Code
// Posting conclusionInput to Mongodb
const postConclusion = async () => {
await axios({
method: "POST",
data: {
conclusion: conclusionInput,
},
withCredentials: true,
url: "http://localhost:4000/conclusion",
}).then((res) => console.log(res));
};
//Backend Node / Express code
app.post("/conclusion", (req, res) => {
console.log("Attempting to post the conclusion");
User.findOne({ username: req.user.username }, async (err, user) => {
if (err) throw err;
if (user) {
(user.conclusion = req.body.conclusion), await user.save();
res.send();
}
});
});
Frontend
In an async function use await and try/catch. Any .then calls can be rolled out into const x = await y variables.
Return values from promise functions, in case you want to use them.
const postConclusion = async () => {
const res = await axios({
method: "POST",
data: {
conclusion: conclusionInput,
},
withCredentials: true,
url: "http://localhost:4000/conclusion",
})
console.log(res)
return res
};
Backend
Again, if you are going with async use that API consistently.
Mongoose provides a promise API, so use that too.
app.post("/conclusion", async (req, res) => {
try {
console.log("Attempting to post the conclusion");
const user = await User.findOne({ username: req.user.username })
if (!user) {
return res.send('not found')
}
user.conclusion = req.body.conclusion
await user.save()
return res.send('saved')
}
catch (error) {
console.error(error)
return res.send('error')
}
});
When using async await, setting an await call to a variable is equal to the parameter in a .then callback
// Frontend React Code
// Posting conclusionInput to Mongodb
const postConclusion = async () => {
// Set the await call to a variable.
const res = await axios({
method: "POST",
data: {
conclusion: conclusionInput,
},
withCredentials: true,
url: "http://localhost:4000/conclusion",
})
// Now no need for .then()!! This is why async/await is so nice.
console.log(res)
};
//Backend Node / Express code
app.post("/conclusion", (req, res) => {
console.log("Attempting to post the conclusion");
User.findOne({ username: req.user.username }, async (err, user) => {
// You need to send the error to the request. Otherwise, the
// request will keep waiting for a response until it times out.
if (err) {
console.error(err)
res.status(500).send(err)
}
if (user) {
// Side note: these should all be on separate lines:
user.conclusion = req.body.conclusion
await user.save();
// You should also send a status code and a response message
res.status(200).send({status: "Success}");
}
});
});
I recommended have a folder called "services" and inside it has yours services by backend.
services/
getData.js
import axios from "axios";
export const getData = () => {
axios.post("http://localhost:4000/conclusion");
};
App.js
import { useEffect, useState } from "react";
import { getData } from "./services/getData";
export default function App() {
const [data, setData] = useState([]); // save the value of service
useEffect(() => {
try {
getData().then((res) => {
setData(res?.data);
});
} catch (e) {
console.error(e);
}
}, []); // execute once
return <div className="App">{data}</div>;
}

Cannot fetch data from Nodejs backend to React frontend

I'm building MERN stack CRUD with goolge login
I'm running my server on port:3001
and frontend on port:3000
getAll() {
return axios.get("http://localhost:3001/jobs")
}
try to fetch data with session loggedin
router.get("/", util.isLoggedin, (req, res) => {
Job.find()
// .populate("author")
.limit(20)
.sort({ jobId: -1 })
.then((jobs) => res.json(jobs))
.catch((err) => res.status(400).json("Error:" + err))
})
const util = {}
util.isLoggedin = function (req, res, next) {
console.log(req.isAuthenticated())
if (req.isAuthenticated()) {
next()
} else {
console.log(req.isAuthenticated())
res.redirect("/")
}
}
module.exports = util
I can retrieve the data only on the server side, not frontend.
what can be the solution?
source code:
https://github.com/jamespark89/mern-communitywebsite
it seems like you are not awaiting your promise..
async getAll() {
return await axios.get("http://localhost:3001/jobs")
}
replace
getAll() {
return axios.get("http://localhost:3001/jobs")
}
with
async getAll() {
return await axios.get("http://localhost:3001/jobs")
}
Try to make your get request as an async function I usualy do that:
router.get("/", util.isLoggedin, async (req, res) => {
try {
const res = await Job.find()
// .populate("author")
.limit(20)
.sort({ jobId: -1 })
res.status(400).json({ res })
} catch(err) {
res.status(400).json("Error:" + err)
}
})

Why does my register user post request fail with a 500 error?

I'm building an app with React and Node/Express, and I'm having trouble with my register user function. The data I am passing in is correct, and other endpoints work fine. The register one keeps returning a 500 error and I can't figure out why.
This is my request:
console.log(values)
axios
.post(
'https://foodtrackr-backend.herokuapp.com/api/register',
values
)
.then(res => {
console.log('res.data', res.data);
})
.catch(error => {
console.log('nope');
console.error(error);
});
};
and this is my endpoint:
router.post('/register', async (req, res) => {
let user = req.body;
const newUser = await Users.add(user);
try {
if (newUser) {
res.status(201).json(user);
} else res.status(404);
} catch (error) {
res.status(500).json('noooooo');
}
});
and this is my model:
function findById(id) {
return (
db('users')
.where({ id })
.first()
);
}
async function add(user) {
const [id] = await db('users').insert(user, 'id');
return findById(id);
}
Any help would be appreciated!

How to get request.session in Vue.js

I'm trying to do authentication in my web site, so I've used express-session and tested with Postman.
Everything go well, but testing with Vue.js it's cannot get session, so how do I get the session on Vue.js.
app.js (Node.js)
router.post('/login', urlencodedParser, ldapAuth, async (req, res) => {
console.log(req.session)
if (!req.session.username) {
res.status(401).send('Auth failed, please log in.');
}
});
router.get('/session', async (req, res) => {
console.log(req.session)
if (req.session.username && req.cookies.user_sid) {
res.status(200).send(req.session)
} else {
res.status(401).send('Auth failed, please log in.');
}
})
login.vue
methods: {
login: e => {
e.preventDefault();
let username = e.target.elements.username.value;
let password = e.target.elements.password.value;
let login = () => {
let data = {
username: username,
password: password
};
PostServices.login(data)
.then(res => {
router.push("/content");
})
.catch(err => console.log(err));
};
login();
}
}
content.vue
methods: {
async getContent() {
const response = await GetServices.fetchSession();
console.log(response);
this.cont = response.session;
}
}
here some console.log output
http request with postman => https://imgur.com/a/EBNyFvT
http request with vue.js => https://imgur.com/a/T3AmPpL

Axios get request is returning user:null using redux actions to make call to the backend?

All my axios post requests are working ok.
Also the get request to postman are working fine, but when i make a get request using axios it is returning user:null from the auth middleware from the app.get request.
here is my my files:
user.actions file:-
export function auth() {
const request =
axios.get(`http://localhost:3001${USER_SERVER}/auth`)
.then(response => response.data)
return {
type: AUTH_USER,
payload: request
}
}
this is the request in my server file:
app.get('/api/users/auth', auth, (req, res) => {
res.status(200).json({
isAdmin: req.user.role === 0 ? false : true,
isAuth: true,
email: req.user.email,
name: req.user.name,
lastname: req.user.lastname,
role: req.user.role,
cart: req.user.cart,
history: req.user.history,
contactnumber: req.user.contactnumber,
address: req.user.address
})
})
Here is my auth middleware:-
const { User } = require('../models/user')
let auth = (req, res, next) => {
let token = req.cookies.x_auth
User.findByToken(token, (err, user) => {
if (err)
throw err
if (!user)
return res.json({
user: user,
isAuth: false,
error: true
})
console.log(user)
req.token = token
req.user = user
next()
})
}
module.exports = { auth }
Here is the reducer from my reducer file:
case AUTH_USER:
return { ...state, userData: action.payload }
here is my auth.js file where i am making the auth request after signing in
from the browser:
class AuthCheck extends Component {
state = {
loading: false
}
componentDidMount() {
this.props.dispatch(auth()).then(Response => {
console.log(this.props.user)
let user = this.props.user.userData
console.log(user)
})
}
render() {
if (this.state.loading) {
return (
<div className='main_loader'>
<Loader size='big' active />
</div>
)
}
return (
<ComposedClass {...this.props} user={this.props.user} />
)
}
}
function mapStateToProps(state) {
return {
user: state.user
}
}
return connect(mapStateToProps)(AuthCheck)
}
The console.log from auth.js file returns:
{user: null, isAuth: false, error: true}
even after i get loginSuccess = true when i login with the registered user.
What is the problem?
Here is my create store file in client's index.js file
const createStoreWithMiddleware = applyMiddleware(promiseMiddleware, ReduxThunk)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(Reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())}>
<BrowserRouter>
<Routes />
</BrowserRouter>
</Provider>
, document.getElementById('root'));
Here is my combine reducer file:
import { combineReducers } from 'redux'
import user from './user_reducer'
const rootReducer = combineReducers({
user
})
export default rootReducer
The issue in your code is that in your reducer file you are setting action.payload to userData but in your component you are accessing as state.user which isn’t right. It should be state.userData
So Change
function mapStateToProps(state) {
return {
user: state.user
}
}
To
function mapStateToProps(state) {
return {
user: state.userData
}
}
So inside render do console.log(this.props.user); you will get the user data
Can you show your combineReducers and createStore functions? Also, your authAction function seems a little off. Try this instead:
export const auth = () => async dispatch {
const response = await axios.get(`http://localhost:3001${USER_SERVER}/auth`);
dispatch({
type: AUTH_USER,
payload: response.data
})
}
Wrap it in a try-catch to handle network errors.

Resources