`mongolab` - getting error on post, not able to post a data - mongodb

I have a account with mongolab(mlab). I am trying to post a data for the users using postman add-on from chrome browser. I am getting error always. I could not able to post a data. I have tried with other diffrent ways. but no luck.
any one help me to sort this issue?
here is my api.js :
var
User = require('../models/user'),
config = require('../../config'),
secretKey = config.secretKey;
module.exports = function( app, express ) {
var api = express.Router();
api.post('/signup', function (req, res) {
var user = new User({
name:req.body.name,
username:req.body.username,
password:req.body.password
});
user.save(function(err){
if(err){
res.send(err);
return;
}
res.json({message:'User has been Created!'});
});
});
api.get('/users', function(req, res) {
User.find({}, function( req, users){
if(err) {
res.send(err);
return;
}
res.json(users);
})
});
return api;
}
config.js :
module.exports = {
"database":"mongodb://xxx:xxxx#ds015700.mlab.com:15700/arifstory",
"port" : process.env.PORT || 3000,
"secretKey" : "YourSecretKey"
}
And the user.js :
var
mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt-nodejs');
var UserSchema = new Schema({
name : String,
userName:{ type:String, required:true, index : { unique: true }},
password : { type:String, required : true, select : false }
});
UserSchema.pre('save', function(next) {
var user = this;
if(!user.isModified('password')) return next();
bcrypt.hash( user.password, null, null, function(err, hash) {
if(err) return next(err);
user.password = hash;
next();
});
});
UserSchema.methods.comparePassword = function( password ) {
var user = this;
return bcrypt.compareSync(password, user.password);
}
module.exports = mongoose.model('User', UserSchema);
I really unable to understand the issue here. please any one help me?
error
{
"message": "User validation failed",
"name": "ValidationError",
"errors": {
"userName": {
"message": "Path `userName` is required.",
"name": "ValidatorError",
"properties": {
"type": "required",
"message": "Path `{PATH}` is required.",
"path": "userName"
},
"kind": "required",
"path": "userName"
},
"password": {
"message": "Path `password` is required.",
"name": "ValidatorError",
"properties": {
"type": "required",
"message": "Path `{PATH}` is required.",
"path": "password"
},
"kind": "required",
"path": "password"
}
}
}

The data sent from chrome could be undefined.
Print it in console by including the below 2 lines above user.save function in api.js file:
console.log(req.body.username);
console.log(req.body.password);
if it shows as undefined, then make sure to check "x-www-form-urlencoded" under "body" in Postman and provide username and password under that.

Related

API call fails when i put required:true model schema

I am trying to make an api endpoint and this is my model schema MongoDB
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema(
{
username: {
type: String,
required: true,
unique: true,
},
email: {
type: String,
},
password: {
type: String,
},
profilePic: {
type: String,
default: "",
},
},
{ timestamps: true }
);
module.exports = mongoose.model("User", UserSchema);
API logic
const router = require("express").Router();
const User = require("../models/User");
//REGISTER
router.post("/register", async (req, res) => {
try {
const newUser = new User({
username: req.body.username,
email: req.body.email,
password: req.body.password,
});
const user = await newUser.save();
res.status(200).json(user);
} catch (err) {
res.status(500).json(err);
}
});
module.exports = router;
index.js
const express = require("express");
const app = express();
const dotenv = require("dotenv");
const mongoose = require("mongoose");
const authRoute = require("./routes/auth");
const cors = require("cors");
const bodyParser = require("body-parser");
app.use(
bodyParser.urlencoded({
extended: false,
})
);
app.use(bodyParser.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use(express.json());
dotenv.config();
mongoose
.connect(process.env.MONGO_URL, {
useUnifiedTopology: true,
useNewUrlParser: true,
})
.then(() => console.log("DB Connected!!!"))
.catch((err) => {
console.log("did not work", err);
});
app.use("/api/auth", authRoute);
app.use("/", (req, res) => {
console.log("main url");
});
app.listen("5002", () => {
console.log("server running");
});
When I am trying to POST call to localhost:5002/api/auth/register , with the following body
{
"username": "testname",
"email": "test#gmail.com",
"password": "122",
}
I get the following error
{
"errors": {
"username": {
"name": "ValidatorError",
"message": "Path `username` is required.",
"properties": {
"message": "Path `username` is required.",
"type": "required",
"path": "username"
},
"kind": "required",
"path": "username"
}
},
"_message": "User validation failed",
"name": "ValidationError",
"message": "User validation failed: username: Path `username` is required."
}
When I remove required:true this api call works but i cant see the fields for username, email, password in collection of the database.
What am I doing wrong here?

why mongoose populate() request does not work?

I try to populate some data from other collection to an other collection.i had googled the search and also i follow the tutorial step by step but the population had fail.any help is appreciate friends. this is the code:
router.get("/", passport.authenticate("jwt", {session: false}), (req, res)=> {
const errors = {};
Profile.findOne({user: req.user.id})
.then(profile => {
if (!profile) {
errors.noprofile = "there is no profile for this user"
return res.status(404).json(errors);
}
res.json(profile);
}).catch(err=> res.status(404).json(err))
});
// #route POST api/profile
//#desc Create or edit user profile
//#access Private
router.get("/", passport.authenticate("jwt", {session: false}), (req, res)=> {
const {errors, isValid} = validateProfileInput(req.body);
//Check validation
if(!isValid) {
return res.status(400).json(errors);
}
// Get profile data
const profileData = {};
profileData.user = req.user.id;
if(req.body.handle) {
profileData.handle = req.body.handle
};
if(req.body.company) {
profileData.company = req.body.company
};
if(req.body.website) {
profileData.website = req.body.website
};
if(req.body.location) {
profileData.location = req.body.location
};
if(req.body.status) {
profileData.status = req.body.status
};
if(typeof req.body.skills !== 'undefined') {
profileData.skills = req.body.skills.split(',');
}
//social
profileData.social = {};
if(req.body.youtube) {
profileData.social.youtube = req.body.youtube
};
if(req.body.twitter) {
profileData.social.twitter = req.body.twitter
};
if(req.body.facebook) {
profileData.social.facebook = req.body.facebook
};
if(req.body.instagram) {
profileData.social.instagram = req.body.instagram
};
Profile.findOne({user: req.user.id})
.populate(
"user",
["name, avatar"]
)
this is the result that I get from the postman :
"_id": "62ee1058ceb295ccdfedffce",
"user": "62e6825958870d3db69d2da5",
"handle": "pablo",
"status": "developper",
"skills": [
"design web"
],
and the correct result must be :
"_id": "62ee1058ceb295ccdfedffce",
"user": {"_id": "62e6825958870d3db69d2da5",
"name": "pablo",
"avatar": "//www.gravatar.com/avatar/1ffsrenbdgeajks-ghsdereys1dkkdhddbc"
}
"handle": "pablo",
"status": "developper",
"skills": [
"design web"
],

Problem setting up node js server to listen for webhook and post to database

Good morning everyone, I'm having a bit of a struggle setting up a server to listen for webhook data and post it to a database. I'm mostly front-end, so some of this is a bit new for me. So I have a deli website that i built on snipcart. I have a receipt printer that queries an api and prints out new orders. So what I'm wanting is a server to listen for the webhook and store the info in a database. I've got it where it listens for the webhook correctly, but it refuses to post to the database. Here's the code in the app.js file.
'use strict';
require('./config/db');
const express = require('express');
const bodyParser = require('body-parser');
const fetch = require('node-fetch');
const app = express();
var routes = require('./api/routes/apiRoutes');
routes(app);
let orderToken;
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
app.listen(process.env.PORT || 8080);
app.post('/hook', (req, res) => {
orderToken = req.body.content.token;
console.log(orderToken);
const secret = "snipcart api key";
const apiFetch = async function(){
};
let buffered = new Buffer.from(secret);
let base64data = buffered.toString('base64');
const start = async function(){
const request = await fetch('https://app.snipcart.com/api/orders/'+orderToken, {
headers: {
'Authorization': `Basic ${base64data}`,
'Accept': 'application/json'
}
});
const result = await request.json();
console.log(result);
};
start();
res.status(200).end();
});
app.get('/', (req, res) => {
res.send('hello world')
});
Here's the code in my apiController.js file
const mongoose = require('mongoose'),
Order = mongoose.model('apiModel');
// listAllOrders function - To list all orders
exports.listAllOrders = (req, res) => {
api.find({}, (err, api) => {
if (err) {
res.status(500).send(err);
}
res.status(200).json(api);
});
};
// createNewOrder function - To create new Order
exports.createNewOrder = (req, res) => {
let newApi = new api (req.body);
newApi.save((err, api) => {
if (err) {
res.status(500).send(err);
}
res.status(201).json(api);
});
};
// deleteOrder function - To delete order by id
exports.deleteOrder = async ( req, res) => {
await api.deleteOne({ _id:req.params.id }, (err) => {
if (err) {
return res.status(404).send(err);
}
res.status(200).json({ message:"Order successfully deleted"});
});
};
and my apiModel.js file
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ApiSchema = new Schema({
customerName: {
type:String,
required:true
},
customerPhone: {
type:String,
required:true
},
name: {
type:String,
required:true
},
orderNumber: {
type:String,
required:true
},
price: {
type:String,
required:true
},
customFields: {
type:Array,
required:false
},
});
module.exports = mongoose.model("apiModel", ApiSchema);
apiRoutes.js
module.exports = function(app){
var orderList = require('../controllers/apiController');
app
.route('/orders')
.get(orderList.listAllOrders)
.post(orderList.createNewOrder);
app
.route('/order/:id')
.delete(orderList.deleteOrder);
};
and my db.js
const mongoose = require("mongoose");
//Assign MongoDB connection string to Uri and declare options settings
var uri = "<mongodb atlas info>
retryWrites=true&w=majority";
// Declare a variable named option and assign optional settings
const options = {
useNewUrlParser: true,
useUnifiedTopology: true
};
// Connect MongoDB Atlas using mongoose connect method
mongoose.connect(uri, options).then(() => {
console.log("Database connection established!");
},
err => {
{
console.log("Error connecting Database instance due to:", err);
}
});
and here's a sample response that I need to place into the database
{
"token": "93c4604e-35ac-4db7-b3f1-2871476e9e6a",
"creationDate": "2013-10-22T20:54:40.377Z",
"modificationDate": "2013-10-22T20:55:45.617Z",
"status": "Processed",
"paymentMethod": "CreditCard",
"invoiceNumber": "SNIP-1427",
"email": "geeks#snipcart.com",
"cardHolderName": "Geeks Snipcart",
"creditCardLast4Digits": "4242",
"billingAddressName": "Geeks Snipcart",
"billingAddressCompanyName": "Snipcart",
"billingAddressAddress1": "4885 1ere Avenue",
"billingAddressAddress2": null,
"billingAddressCity": "Quebec",
"billingAddressCountry": "CA",
"billingAddressProvince": "QC",
"billingAddressPostalCode": "G1H2T5",
"billingAddressPhone": "1-877-301-4813",
"notes": null,
"shippingAddressName": "Geeks Snipcart",
"shippingAddressCompanyName": "Snipcart",
"shippingAddressAddress1": "4885 1ere Avenue",
"shippingAddressAddress2": null,
"shippingAddressCity": "Quebec",
"shippingAddressCountry": "CA",
"shippingAddressProvince": "QC",
"shippingAddressPostalCode": "G1H2T5",
"shippingAddressPhone": "1-877-301-4813",
"shippingAddressSameAsBilling": true,
"finalGrandTotal": 287.44,
"shippingFees": 10,
"shippingMethod": "Shipping",
"items": [
{
"uniqueId": "1aad3398-1260-419c-9af4-d18e6fe75fbf",
"id": "1",
"name": "Un poster",
"price": 300,
"quantity": 1,
"url": "http://snipcart.com",
"weight": 10,
"description": "Bacon",
"image": "",
"customFieldsJson": "[]",
"stackable": true,
"maxQuantity": null,
"totalPrice": 300,
"totalWeight": 10
},
...
],
"taxes": [
{
"taxName": "TPS",
"taxRate": 0.05,
"amount": 12.5,
"numberForInvoice": ""
},
{
"taxName": "TVQ",
"taxRate": 0.09975,
"amount": 24.94,
"numberForInvoice": ""
},
...
],
"rebateAmount": 0,
"subtotal": 310,
"itemsTotal": 300,
"grandTotal": 347.44,
"totalWeight": 10,
"hasPromocode": true,
"totalRebateRate": 20,
"promocodes": [
{
"code": "PROMO",
"name": "PROMO",
"type": "Rate",
"rate": 20,
},
...
],
"willBePaidLater": false,
"customFields": [
{
"name":"Slug",
"value": "An order"
},
...
],
"paymentTransactionId": null,
}
I dont need all the info placed in the database, just a few key items, like customer name, phone number and the order info. but if there's more than one item in the order, I need it to take that into account and add all the items in the order. here is the docs for the printer that i'm needing to integrate https://star-m.jp/products/s_print/CloudPRNTSDK/Documentation/en/index.html Would appreciate any help that you all can give me. Thanks!
Snipcart will send the webhook to you endpoint for different events. I would suggest you to first filter the event by eventName, because you want to listen for only the order.completed event. After that from the body of the request message, you can extract the items that will be in the req.body.content.items. You can take from the available info what you want and store only that in the database.
Try this:
app.post('/hook', (req, res) => {
if (req.body.eventName === 'order.completed') {
const customer_name = req.body.content.cardHolderName;
const customer_phone req.body.content.billingAddressPhone;
const order_number = req.body.content.invoiceNumber;
let items = [];
req.body.content.items.forEach((item) => {
items.push({
name: item.name,
price: item.price,
quantity: item.quantity,
id: item.uniqueId
});
})
// Now store in database
apiFetch.create({
customerName: customer_name,
customerPhone: customer_phone
name: customer_name,
orderNumber: order_number
customFields: items
}).then(()=>{
res.status(200).json({success:true});
}, (error)=>{
console.log('ERROR: ', error);
})
}
};

Mongoose Path "." is required - problem with PostmanMocking?

i am testing my mongoose (for MongoDB) schema, and I encountered an validation issue. After making POST verb I am getting en error:
"message": {
"errors": {
"number": {
"message": "Path `number` is required.",
"name": "ValidatorError",
"properties": {
"message": "Path `number` is required.",
"type": "required",
"path": "number"
},
"kind": "required",
"path": "number"
}
},
"_message": "eventArrayModel validation failed",
"message": "eventArrayModel validation failed: number: Path `number` is required.",
"name": "ValidationError"
}
This is my mocked json in Postman:
JSON mocked file
{
"arrayName": "displayedEvents",
"number": "4"
}
And this is my mongoose schema:
const mongoose = require("mongoose");
const eventSchema = new mongoose.Schema({
title: {
type: String,
// required: true,
},
start: {
type: Date,
// required: true,
},
end: {
type: Date,
// required: true,
},
allDay: {type: Boolean, default: true},
resource: {
type: String,
// required: true,
},
});
const eventArrayModel = mongoose.model("eventArrayModel", {
arrayName: {
type: String,
required: true,
},
array: {type: [eventSchema]} ,
number: {
type: Number,
required: true,
}
});
module.exports = eventArrayModel;
And the get router:
router.get('/', async (req,res)=> {
try{
const posts = await eventArrayModel.find();
res.json(posts);
}catch(err){
res.json({message: err});
}
});
I can't see anything wrong about this code. It works fine without number field.
Okey I found it, this part of code
router.post('/', async(req,res)=>{
const post = new eventArrayModel({
arrayName: req.body.arrayName
});
try {
const savedPost = await post.save();
res.json(savedPost);
}catch(err){
res.json({message: err});
}
});
Should looks more like this:
router.post('/', async(req,res)=>{
const post = new eventArrayModel({
arrayName: req.body.arrayName,
array: req.body.array,
myNumber: req.body.myNumber
});
try {
const savedPost = await post.save();
res.json(savedPost);
}catch(err){
res.json({message: err});
}
});

Mongoose schema optional with validation

Given a Schema like this:
new Schema(
{
someData: {
someString: {
required: false,
maxlength: 400,
type: String
}
otherData: {
required: true,
type: String
}
});
someString is optional but has a validation to check if it's length is below 400.
If I'm given an invalid length string (>400) would this object still be saved but without the someString or would this throw an error? If this throws an error how can I change the schema so that the object will still get saved?
It will throw an error without saving the document.
Let's say we have this schema:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const studentSchema = new Schema({
someData: {
someString: {
required: false,
maxlength: 5,
type: String
},
otherData: {
required: true,
type: String
}
}
});
module.exports = mongoose.model("Student", studentSchema);
And this post route:
const Student = require("../models/student");
router.post("/students", async (req, res) => {
try {
const result = await Student.create(req.body);
res.send(result);
} catch (err) {
console.log(err);
if (err.name === "ValidationError") {
return res.status(400).send(err.errors);
}
res.status(500).send("Something went wrong");
}
});
When we send a bad request it will give ValidationError where we can read the error details from err.errors.
Request Body:
{
"someData": {
"someString": "123456",
"otherData": "other"
}
}
The response will be:
{
"someData.someString": {
"message": "Path `someData.someString` (`123456`) is longer than the maximum allowed length (5).",
"name": "ValidatorError",
"properties": {
"message": "Path `someData.someString` (`123456`) is longer than the maximum allowed length (5).",
"type": "maxlength",
"maxlength": 5,
"path": "someData.someString",
"value": "123456"
},
"kind": "maxlength",
"path": "someData.someString",
"value": "123456"
}
}
You can resolve this by removing the maxlength option, or check the field's length in your route, and if it's length is bigger than the specified maxlength, you can substr it so that it doesn't result in error.
router.post("/students", async (req, res) => {
try {
let doc = req.body;
if (doc.someData && doc.someData.someString && doc.someData.someString.length > 5) {
doc.someData.someString = doc.someData.someString.substring(0, 5);
}
const result = await Student.create(doc);
res.send(result);
} catch (err) {
console.log(err);
if (err.name === "ValidationError") {
return res.status(400).send(err.errors);
}
res.status(500).send("Something went wrong");
}
});