problem on creating new document in mongoose - node.js

i want to add a new document with mongoose
but it just creates only the _id without all the details I entered
in the postman i entered:
{
"name":"jhon",
"email":"jhon11#gmail",
"password":"1234"
}
but got this in the res:
{
"_id": "6072e8d3f0f69037cc05b8cb",
"__v": 0
}
my code:
const addUser = async (req, res) => {
try {
let user = new User(req.body)
await user.save()
res.send(user)
}
catch (error) {
res.status(400).send(`error ${error}`)
}
}
and the schema is:
const userSchema=mongoose.Schema({
name:{
Type:String
},
email:{
Type:String
},
password:{
Type:String,
}
})
thanks for any advice.

Postman isn't very straight forward in explaining how it sends out post requests. I'm saying this because I also had some run-downs with it. It is most likely sending out an empty body in the request. Open up postman again, and go to the post request you created. We already know your request reached the backend server, so it means the url is fine, and that its type is in fact a post request. So now, click on the Body tab.
I'm gonna go ahead and guess you chose the raw option amongst the million available options there, correct?
In the textarea zone, insert your raw json again, as you did before:
{
"name":"jhon",
"email":"jhon11#gmail",
"password":"1234"
}
But wait! before sending that out, look to the right. There's a combo-box there. A dropdown. A select menu (whatever you wanna call it).
By default, postman chooses TEXT as the default option. Change it to JSON!
NOW IT'S GONNA WORK!
Also, maybe before sending that out for test spin, i'd recommend putting a console.log in bewtween your lines and see what prints out, like so:
const addUser = async (req, res) => {
try {
let user = new User(req.body)
console.log('req.body is:', req.body)
await user.save()
res.send(user)
}
catch (error) {
res.status(400).send(`error ${error}`)
}
If your req.body is still being presented as empty, then my next question to you would be: Are you using bodyParser on your server? Because could also be the case. Body parser, as its name suggests, is meant for dealing with req.body, so it could actually be readable. try adding a body parser to your express server.
Good luck!
I hope that helps.

Related

Getting an empty object in Axios Get Request

I am trying to set up a get route using axios. I am using React. I am trying to get the state of user.
user.user logs:
{_id: '62c5bdda933b818e12bef350', username: 'JordanF', Profiles: Array(9), createdAt: '2022-07-06T16:52:42.396Z', updatedAt: '2022-07-09T19:24:10.523Z', …}
I am trying to display username on my page. But at the moment I can't even log the username to my backend, so won't be able to search my db.
Profile.jsx
function getUser(data) {
console.log(data)
axios({
url: `http://localhost:3000/profiles`,
method: "GET",
data: data
})
.then((response) => console.log(response))
}
useEffect(() => {
setProfileList(profiles)
getUser(user.user)
},[]);
Data logs the data in the front end that I would like to get in the backend
BackEnd Controller
I have tried a lot of different syntax for this, this is my most recent. In the backend temrinal my console.log hits, and req.body returns an empty object.
async function getUser(req,res){
console.log('getUser hit')
function log(){
console.log(req.body)
return req.body
}
await log()
}
Yup! I was being silly. GET requests are only really concerned with params. I changed my route, so that the User's ID was in the URL path, and used req.params.id and everything worked out!

Using Express and Axios, Axios will not recognize PUT Requests

I have dumbed down my use case to a simple test, in which I click a button and an UPDATE put request is sent using an axios API. Three other request methods-- post, get, and delete, all work properly and are recognized. My PUT method, however, gives a 404 Not Found error, as though I havent established the method with express in my server.
This is the code for the request, triggered by this event handler (for the button):
const handleUpdate = async (e, id) => {
e.stopPropagation();
// navigate(`/restaurants/${id}/update`);
//update test
try {
const updatedRestaurant = await RestaurantFinder.put(`/${id}`, {
name: "taco bell",
location: "dogtown",
price_range: "2"
});
console.log(updatedRestaurant);
navigate("/");
} catch(err) {
console.log(err);
}
};
This is the api's instantiation:
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:3001/api/v1/restaurants"
}
);
This is the request in Express. Note that the first log "does this exist???" is never displayed. The address for the put request to "http://localhost:3001/api/v1/restaurants/id" is never found.
//UPDATE a restaurant
app.put("/api/v1/restaurants/:id"), async (req, res) => {
console.log("does this exist???");
try {
const results = await db.query(
"UPDATE restaurants SET name = $1, location = $2, price_range = $3 where id = $4 returning *",
[req.body.name, req.body.location, req.body.price_range, req.params.id]
);
res.status(200).json({
status: "succes",
data: {
restaurant: results.rows[0],
},
});
} catch (err) {
console.log(err);
}
console.log(req.params.id);
console.log(req.body);
};
I have pored over StackOverflow for answers, I think I've viewed over 50 posts at this point. This is something that should be so simple, and yet I can't find a single answer for it or see where it's happening to anyone else.
If anyone could please help walk me through what is going wrong, I would be so grateful!
Edit 1 #Stephen:
const app = express();
app.use(cors(
{
methods: ["POST", "GET", "DELETE", "PUT"]
}
));
app.use(express.json());
So i changed it to this with no luck. Originally i was just using cors(), and my understanding is that it defaults to allowing a put method.
Does your server allow the put method? Perhaps your server only allows the others in the access-control-allow-methods field.
See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
For testing over http, make sure both of these are set by your server.
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS

Why express validator oneOf is not working as expected

I'm building a project in NodeJS and I'm also using Express. To validate my requests from the client I'm using Express validator and the methods check, oneOf, body, and etc.
I built my PUT endpoint and in parallel also I implemented a validation for the fields to update using oneOf. My goal is that when a client tries to update should at least change one of the fields otherwise a message should come ups informing the client nothing was updated.
My issue is that the PUT updates ignoring my check I implemented and cannot understand the issue as I already did similar before and was working perfectly.
My validator for update looks like:
const updateBookRules = [
oneOf([
check("title")
.exists()
.withMessage("Title is required"),
check("category")
.exists()
.withMessage("Category is required"),
check("price")
.isNumeric()
.withMessage("Price should be a number"),
check("img")
.exists()
.withMessage("Img is required"),
sanitizeBody("price").toFloat()
])
];
In the route, I'm calling this validation as:
// PUT Update a book
router.put("/:asin", check.updateBook, check.rules, async (req, res) => {
// Request ID
const asin = req.params.asin;
// Await the book
await book
// Call model to update the product
.updateBook(asin, req.body)
// Response a message
.then(book =>
res.json({
message: `The book #${asin} has been updated`,
content: book
})
)
// Errors if any
.catch(err => {
if (err.status) {
res.status(err.status).json({ message: err.message });
}
res.status(500).json({ message: err.message });
});
});
The strange is the validation is ignored and I can put also empty strings and no error happens I don't know what is my mistake.
Please comment if you would like to see something more and I will update the question.
Edited Answer
I think I may know the issue. Your code seems fine now that I've had access to the whole repo, but you definitely need to be bringing in validationResult in order to check for validation errors, then stop execution of the router middleware. So, the router.put route-handler would start with:
const { validationResult } = require('express-validator');
// PUT Update a book
router.put("/:asin", check.updateBook, check.rules, async (req, res) => {
// Finds the validation errors in this request and wraps them in an object with handy functions
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
I'm still not sure about how you setup updateBookRules to use the sanitizeBody() call, and how you have it wrapped in an array. If the above still doesn't work after adding validationResult, try this:
const updateBookRules = oneOf([
check("title")
.exists()
.withMessage("Title is required"),
check("category")
.exists()
.withMessage("Category is required"),
check("price")
.isNumeric()
.withMessage("Price should be a number"),
check("img")
.exists()
.withMessage("Img is required"),
]);
Then make the route-handler signature:
router.put("/:asin", sanitizeBody("price").toFloat(), check.updateBook, check.rules, async (req, res) => {
Also, are you sure there is an error? The docs state that oneOf :
Creates a middleware instance that will ensure at least one of the
given chains passes the validation.
You are checking to make sure that these different fields exist at the PUT route. As long as one of them does exist, check.updateBook will pass. You aren't checking for change here, so the user can simply send you back the same book information, and nothing will fail right?
Per your comments, if you really don't want to use the validationResult you can try to run the validations imperatively, check out the docs

Perform POST from Browser URL

I have a functionality of verifying a user by clicking a link from Email. I have field in Mongo User Collection called Active. This is a boolean. when User register, Active will be false. When they click the link active will change to true. My issue is that link is working well in postman but not working in browser URL.
My Code
verify = (req, res) => {
User.update({ email: req.query.mail }, { $set: { active: true } }, (err, user) => {
if (err) {
res.send(err);
} else {
res.send(user);
}
});
}
My API: POST api/user/verifySignin
My Link: http://localhost:3000/api/user/verifySignin?mail=abc#xyz.com
I used this link in browser URL its not working, But I used in POSTMAN its working. Help me, where I am going wrong
You can't make post requests from an URL directly in your browser, you need to either use an XMLHTTP request library like fetch or use a <form action="http://localhost:3000/api/user/verifySignin?mail=abc#xyz.com" method="post">
try $http to pass the url
$http.post(http://localhost:3000/api/user/verifySignin)

Setting a test header in GraphQL Playground that I want to use causes "Server cannot be reached"

So I've created a bunch of mutations and queries and stitched them together that works and wanted to introduce authentication into the mix. I added an HTTP Header "x-token" to hold my sign-in token to be able to delete things like their job or the user itself.
const getMe = async req => {
const token = req.headers['x-token'];
if (token) {
try {
return await jwt.verify(token, "notSoSecret");
} catch (e) {
throw new AuthenticationError(
'Your session expired. Sign in again.',
);
}
}
};
const server = new ApolloServer({
typeDefs: schema,
resolvers,
formatError: error => {
// remove the internal sequelize error message
// leave only the important validation error
const message = error.message
.replace('SequelizeValidationError: ', '')
.replace('Validation error: ', '');
return {
...error,
message,
};
},
context: async ({ req }) => {
const me = await getMe(req);
return {
models,
me,
secret: "notSoSecret",
}
},
path: "/graphql"
});
server.applyMiddleware({ app });
sequelize.sync().then(async () => {
createUsersWithJob();
});
app.get("/playground", graphiql({ endpoint: "/graphql" }));
const handler = serverless(app);
export { handler };
const createUsersWithJob = ... //creates seed data
So when I add the token and I look into my command line console, I actually see that I'm setting the header that I want, but it loops over and over again and doesn't stop. Also playground gets an error "Server cannot be reached"
{
"error": "Response not successful: Received status code 400"
}
and running a deleteUser mutation does not work, or any other mutation and query for that matter until I remove the HTTP Header that I set on playground.
There is a secondary issue where everything in this root file runs twice, but that's not as big for me at the moment as the header issue outlined.
If anyone has any insight into this, I'd love to know more. Thanks in advance.
edit: just a quick edit to say that it works fine when I hardcode a pre-existing user.
I had quite a struggle to get the React version of GraphQL Playground working within a very simple html setup, but I figured something out that might help you as well (fingers crossed).
I added a headers section to the config in the GraphQLPlayground.init call, like so:
const root = document.getElementById('root');
GraphQLPlayground.init(root, {
endpoint: "/graphql",
headers: {
"Authorization": "Bearer " + token
}
})
I have an element with an id root since this is embedded in HTML.
Not sure this will help you though, as I just noticed from your code sample you're calling graphiql which is a different GraphQL client than GraphQL Playground..
GraphIQL: https://github.com/skevy/graphiql-app
GraphQL Playground: https://github.com/prisma/graphql-playground

Resources