0
I have been banging my head the long hours trying to figure why my PUT and DELETE request does not work. It returns a 404 not found response. My POST and GET all work fine.
I use chrome postman
app.put('api/courses/:id', (req, res) => {
const course = courses.find(c => c.id === parseInt(req.params.id));
if (!course) return res.status(404).send('This course with the given id was not found');
const { error } = validateCourse(req.body);
if (error)
return res.status(400).send(error.details[0].message);
course.name = req.body.name;
res.send(course);
});
app.delete('api/courses/:id', (req, res) => {
const course = courses.find(c => c.id === parseInt(req.params.id));
if (!course) return res.status(404).send('this course with the given ID is not valid');
const index = courses.indexOf(course);
courses.splice(index, 1)
res.send(course);
})
function validateCourse(course) {
const schema = {
name: Joi.string().min(3).required()
};
return Joi.validate(course, schema);
}
I am trying to create a simple api in Node.js. The http method is not working
Add a leading / to the route definitions:
app.put('/api/courses/:id', ...);
There is no such thing as relative routes on the server.
Related
I am trying to do a MVC architecture tutorial from Codecademy's website: https://www.codecademy.com/article/mvc-architecture-for-full-stack-app
I finished the tutorial but when I run everything, I get this error:
It seems that what I'm returning is not valid JSON. So I think the problem is that the endpoint may be causing the error. But I'm not too sure. Here is the code where the error is triggered:
src/utils/index.js:
export const fetchExpenses = async (date) => {
const selectDate = new Date(date).getTime() || new Date().getTime();
const res = await fetch(`/api/expense/list/${selectDate}`);
console.log('result',res);
return res.json();
};
Here is the code from app.js in the "view" portion of my code:
useEffect(() => {
// update view from model w/ controller
fetchExpenses().then((res) => setExpenses(res));
}, []);
It seems the problem is the communication between the view and the controller. When I create an expense, it actually is updated in the database:
Any ideas why this error is happening?
Edit 1:
Here is the network response when I try to create a new expense in my application. So it seems that when I create a new expense, the fetchExpenses() is automatically called to display a list of current expenses.
this the raw response I get from fetchExpenses() :
Edit 2:
Here is what the header shows from the response:
The endpoint is causing the error, but I'm not sure why. Here is the endpoint:
export const createExpense = async (data) => {
const res = await fetch(`/api/expense/create`, {
method: 'POST',
body: data,
});
return resHandler(res, 201);
};
and here is resHandler() which createExpense() returns:
export const resHandler = async (res, status) => {
if (res.status === status) {
return null;
}
const data = await res.json();
if (data && data.emptyFields) {
return data.emptyFields;
}
return null;
};
Here is the code from the controller when an expense is created:
exports.create = (req, res) => {
const form = new formidable.IncomingForm();
form.keepExtensions = true;
form.parse(req, async (err, fields) => {
const { title, price, category, essential, created_at } = fields;
// check for all fields
if (fieldValidator(fields)) {
return res.status(400).json(fieldValidator(fields));
}
try {
const newExpense = await pool.query(
'INSERT INTO expenses (title, price, category, essential, created_at) VALUES ($1, $2, $3, $4, $5)',
[title, price, category, essential, created_at]
);
return res.status(201).send(`User added: ${newExpense.rows}`);
} catch (error) {
return res.status(400).json({
error,
});
}
});
};
Edit 3
Here is the route /api/expense/list/{dateTime}:
const express = require('express');
const router = express.Router();
const { create, expenseById,
read, update, remove, expenseByDate } = require('../controllers');
router.get('/expense/list/:expenseDate', expenseByDate, read);
module.exports = router;
And here is my controllers.js that deal with the route above:
exports.expenseByDate = async (req, res, next, date) => {
try {
const expenseQuery = await pool.query(
'SELECT * FROM expenses WHERE created_at BETWEEN $1 AND $2',
[
startOfDay(new Date(Number(date))).toISOString(),
endOfDay(new Date(Number(date))).toISOString(),
]
);
const expenseList = expenseQuery.rows;
req.expense =
expenseList.length > 0
? expenseList
: `No expenses were found on this date.`;
return next();
} catch (error) {
return res.status(400).json({
error,
});
}
};
exports.read = (req, res) => res.json(req.expense);
The reason you are getting an Unhandled Rejection (SyntaxError): Unexpected end of JSON input error is because your client app is expecting a JSON response and the express app /api/expense/list/{dateTime} route is not returning valid JSON.
The app is not returning valid JSON because the expenseByDate controller callback has an incorrect function signature so it is not getting called.
exports.expenseByDate = async (req, res, next, date) => <-- "date" is not a valid parameter.
This leads the read controller to return an undefined value to the json response.
exports.read = (req, res) => res.json(req.expense); <-- req.expense is undefined.
res.json(undefined) ultimately returns an empty response to the client which can't be parsed and thus an error is thrown.
Solution
You can fix this error by correcting the expenseByDate controller to have a valid function signature by removing the fourth method parameter. To access a route parameter you should use req.params.
exports.expenseByDate = async (req, res, next, date) => {
const date = req.params.expenseDate;
...
}
This is my middleware,
export const parseUser = (req, res, next) => {
const token_header = req.header('Authorization');
if (token_header) {
req.user = jwt_decode(token_header.split(' ')[1].split(' ')[0]);
req.token = token_header.split(' ')[1].split(' ')[0];
next();
} else {
next();
}
};
this is my router,
router.get('/get/', parseUser, swaggerValidation.validate,
async(req, res) => {
...
} catch (err){
...
}
});
i am trying to mock the parseUser function and assign req.user and req.token values using jest and pass it, i need those values to authorize user and need the value assigned to do database query, I am using jest to mock the functions, I have tried google and stackoverflow, i was not able to solve it with those example, i have tried below methods and others,
jest.mock('../../utils/permission');
const mockedParseUser = jest.mocked(parseUser, true)
mockedParseUser.mockReturnValueOnce({req.user: "value", req.token: "value");
i have also tried,
const return = {req.user: "value", req.token: "value"}
const mockedReturn = jest.fn((): any => return}
jest.spyOn('../../utils/permission', parseUser).mockImpementation((): any => mockReturn())
Nothing worked for me, can someone help me with mocking the parseUser().
I've got some checkuser middleware that stores the user entry when a JWT is verified. However, when I include it in my routes and try to console.log(res.locals.user.username) I get the username logged twice. When I'm trying to store this username in some JSON, its creating a seperate JSON with {username: ___} that is causing issues in Mongoose. Help would be appreciated, thanks.
const checkUser = async (req, res, next) => {
const token = req.cookies.jwt
if (token) {
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, async (err, decodedToken) => {
if (err) {
res.locals.user = null
console.log(err.message)
next()
}
else {
const user = await User.findById(decodedToken.id)
res.locals.user = user
next()
}
})
}
else {
res.locals.user = null
next()
}
}
app.post('*', checkUser) //all routes
app.post('/newuser', requireAuth, async (req, res) => {
let user = res.locals.user
console.log(res.locals.user.username)
let user_req_body = req.body
let starter_workout = {}
starter_workout.username = user.username
user_req_body.username = user.username
if (user_req_body.FitnessMode == 'cardio') {
starter_workout.workout = cardio
starter_workout.workout_name = 'Default Cardio'
}
else if (user_req_body.FitnessMode == 'hypertrophy') {
starter_workout.workout = hypertrophy
starter_workout.workout_name = 'Default Hypertrophy'
}
else if (user_req_body.FitnessMode == 'powerlifting') {
starter_workout.workout = powerlifting
starter_workout.workout_name = 'Default Powerlifting'
}
else if (user_req_body.FitnessMode == 'calisthenics') {
starter_workout.workout = calisthenics
starter_workout.workout_name = 'Default Calisthenics'
}
const user_info = new userInfo(user_req_body)
const workout_info = new routines(starter_workout)
/*
await user_info.save()
.then(resp => console.log(resp))
.catch(err => console.log(err))
await workout_info.save()
.then(resp => console.log(resp))
.catch(err => console.log(err))
This code will send duplicated data to MongoDB. Also worth noting that this happens only with app.use(express.json()). I guess thats where I would need help with some work-around. Thank you.
If console.log(res.locals.user.username) inside of this:
app.post('/newuser', ...)
is outputting twice, then that's because your server is getting two posts requests to /newuser. A common reason for that is if this comes from a <form> in your web page that you are also sending an ajax call from javascript in the page. If you don't properly use e.preventDefault() to prevent the default post that the browser does automatically, then you will get duplicate post requests. To look into that more, we'd have to see how the /newuser request comes from the web page.
I'm trying to write a constraint code that will display a message when someone tries to search for an id that doesn't exist in the database (PostgreSQL) but the if statement code below doesn't seem to do anything I keep getting status 200 ok on postman even though the id doesn't seem to exist. How can I fix this?
Code below:
Database query:
const findFruit = async (req, res) => {
const {id } = req.params;
try {
const findfru = await pool.query("SELECT * FROM fruits WHERE fruit_id=$1", [id]);
if (!findfru ) {
return res.status(400).send(e)
}
res.json(findfru .rows[0])
} catch (e) {
res.status(500).send(e)
}
}
Route API:
router.get("Fruits/:id", findFruit )
If the ID isn't in the database the query still succeeds, it just returns no rows. You should check the number of rows explcitily:
if (findfru.rows.length === 0) {
return res.status(400).send(`${id} not found`);
}
I'm trying to return a value out of an array of values I get from querying Datastore.
results[0] have this content: {"prod_name":"Muffin","prod_price":3.99}.
I'd like to return via res.send only: 3.99
I've tried results[0].prod_price, or results[0]['prod_price'], I have tried saving results[0] as variable and trying to return prod_price, but nothing works.
Any help is appreciated.
My code is here:
const Datastore = require('#google-cloud/datastore');
const Storage = require('#google-cloud/storage');
// Instantiates a client
const datastore = Datastore();
const storage = new Storage();
exports.getprice = function getprice (req, res) {
const kind = datastore.createQuery("Dialogflow");
const filter = kind.filter("prod_name", req.body.queryResult.parameters['bakery_items']);
return query = datastore.runQuery(kind)
.then( (results) => {
const entities = results[0];
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ "fulfillmentText": entities}));
})
.catch((err) => {
console.error(err);
res.status(500).send(err);
return Promise.reject(err);
});
};
I got it.
Actually I kept results instead of forcing results[0], and realized the output had an extra array, so to access the value, I had to do: results[0][0]['prod_price']
Thanks to JavaScript console.