Images not appearing in the MongoDB database - node.js

I am uploading a form that contains an image to my mongodb database, all the data is there as should be however the images are not appearing on the database. Does it have anything to do with the fact i an unable to add propertyImage: req.file.path as I get the error of 'typeError cannot read property of 'path' od undefined'. The reason I want them in the database is to enable me to fetch them and attach the images to the relevant product.
I have the backend code below, as for the front end I am going to assume that I need to create something with formData in order to send the the text fields with the image. If so could someone point me in the right direction as I am not sure where to start so that It wont affect my user authorization set up as detailed below.
const express = require('express');
const userRouter = express.Router();
const passport = require('passport');
const passportConfig = require('../passport');
const JWT = require('jsonwebtoken');
const User = require('../models/User');
const Property = require('../models/Property');
const multer = require('multer')
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, "./uploads/");
},
filename: (req, file, callback) => {
callback(null, file.originalname);
}
})
const upload = multer({storage: storage});
const signToken = userID => {
return JWT.sign({
iss : "Moove",
sub : userID
},"Moove",{expiresIn :"1h"});
}
userRouter.post('/register',(req,res)=>{
const {username,name,email,password} = req.body;
User.findOne({email},(err,user)=>{
if(err)
res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
if(user)
res.status(400).json({message : {msgBody: "Email has already been used, Please log in", msgError : true}});
else{
const newUser = new User({username,name,email,password});
newUser.save(err=>{
if(err)
res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
else
res.status(201).json({message : {msgBody: "Account Successfully Created", msgError : false}});
});
};
});
});
userRouter.post('/login',passport.authenticate('local',{session : false}),(req,res)=>{
if(req.isAuthenticated()){
const {_id,username,password} = req.user;
const token = signToken(_id);
res.cookie('access_token',token,{httpOnly: true, sameSite:true});
res.status(200).json({isAuthenticated : true,user : {username,password}});
}
});
userRouter.get('/logout',passport.authenticate('jwt',{session : false}),(req,res)=>{
res.clearCookie('access_token');
res.json({user:{username:''},success : true})
});
userRouter.post('/property', upload.single('propertyImage'),passport.authenticate('jwt',{session : false}),(req,res)=>{
console.log(req.file);
const property = new Property({
street: req.body.street,
town: req.body.town,
area: req.body.area,
PostCode: req.body.PostCode,
NoBeds: req.body.NoBeds,
NoBath: req.body.NoBath,
NoLivingRooms: req.body.NoLivingRooms,
askingPrice: req.body.askingPrice,
propertyImage: req.file
});
property.save(err=> {
if(err)
res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
else{
req.user.properties.push(property);
req.user.save(err=> {
if(err)
res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
else
res.status(200).json({message: {msgBody: "Successfully created property", msgError : false}});
})
}
})
});
userRouter.get('/properties',passport.authenticate('jwt',{session : false}),(req,res)=>{
User.findById({_id : req.user._id}).populate('properties').exec((err,document)=>{
if(err)
res.status(500).json({message : {msgBody : "Error has occured", msgError: true}});
else{
res.status(200).json({properties : document.properties, authenticated : true});
}
});
});
userRouter.get('/property',passport.authenticate('jwt',{session : false}),(req,res)=>{
User.findById({_id : req.user._id}).populate('properties').exec((err,document)=>{
if(err)
res.status(500).json({message : {msgBody : "Error has occured", msgError: true}});
else{
res.status(200).json({properties : document.properties, authenticated : true});
}
});
});
userRouter.get('/authenticated',passport.authenticate('jwt',{session : false}),(req,res)=>{
const {username} = req.user;
res.status(200).json({isAuthenticated : true, user: {username}})
});
module.exports = userRouter;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import React, {useState,useContext, useEffect} from 'react'
import PropertyItem from './PropertyItem';
import PropertyService from '../Services/PropertyService';
import Message from './Message'
import {AuthContext} from '../Context/AuthContext';
const Properties = props =>{
const [property,setProperty] = useState({
// propertyImage: "",
street : "",
town : "",
area : "",
PostCode : "",
NoBeds : "",
NoBath : "",
NoLivingRooms : "",
askingPrice: "",
})
const [properties,setProperties] = useState ([]);
// const [propertyImage,setPropertyImage] = useState ([]);
const [message,setMessage] = useState(null);
const authContext = useContext(AuthContext);
useEffect(()=>{
PropertyService.getProperties().then(data =>{
setProperties(data.properties);
});
},[]);
const onSubmit = e =>{
e.preventDefault();
PropertyService.postProperty(property).then(data =>{
const {message } = data;
resetForm();
if(!message.msgError){
PropertyService.getProperties().then(getData =>{
setProperties(getData.properties);
setMessage(message);
});
}
else if(message.msgBody === "UnAuthorized"){
setMessage(message);
authContext.setUser({username : ""});
authContext.setIsAuthenticated(false);
}
else{
setMessage(message);
}
},[]);
}
const onChange = e =>{
setProperty({...property,[e.target.name] : e.target.value})
}
// const onChangefile = e =>{
// setPropertyImage(e.target.files[0])
// }
const resetForm = ()=>{
setProperty({
propertyImage: "",
street : "",
town : "",
area : "",
PostCode : "",
NoBeds : "",
NoBath : "",
NoLivingRooms : "",
askingPrice : "",
});
}
return(
<div>
<ul className="">
{
properties.map((property) =>{
return <PropertyItem key={property._id}
property={property}
street={property.street}
town={property.town}
area={property.area}
PostCode={property.PostCode}
NoBeds={property.NoBeds}
NoBath={property.NoBath}
NoLivingRooms={property.NoLivingRooms}
askingPrice={property.askingPrice}
propertyImage={property.propertyImage}
/>
},[])
}
</ul>
<br/>
<form onSubmit={onSubmit} encType="multipart/form-data">
<label htmlFor="street">Street Name</label>
<input type="text"
name="street"
value={property.street}
onChange={onChange}
className=""
placeholder="street name"/>
<label htmlFor="town">Town</label>
<input type="text"
name="town"
value={property.town}
onChange={onChange}
className=""
placeholder="town"/>
<label htmlFor="area">Area</label>
<input type="text"
name="area"
value={property.area}
onChange={onChange}
className=""
placeholder="area"/>
<label htmlFor="postcode">Postcode</label>
<input type="text"
name="PostCode"
value={property.PostCode}
onChange={onChange}
className=""
placeholder="Postcode"/>
<label htmlFor="NoBeds">Beds</label>
<input type="number"
name="NoBeds"
value={property.NoBeds}
onChange={onChange}
className=""
placeholder="Number of beds"/>
<label htmlFor="NoBath">Bathrooms</label>
<input type="number"
name="NoBath"
value={property.NoBath}
onChange={onChange}
className=""
placeholder="Number of bathrooms"/>
<label htmlFor="NoLivingRooms">Living Rroom</label>
<input type="number"
name="NoLivingRooms"
value={property.NoLivingRooms}
onChange={onChange}
className=""
placeholder="Number of living rooms"/>
<label htmlFor="askingPrice">Asking Price(£)</label>
<input type="number"
name="askingPrice"
value={property.askingPrice}
onChange={onChange}
className=""
placeholder="£249,999"/>
<label htmlFor="propertyImage">Property Images</label>
<input type="file"
filename="propertyImage"
onChange={onChange}
className=""
placeholder="Upload property images"/>
<button className=""
type="submit">Submit</button>
</form>
{message ? <Message message={message}/> : null}
</div>
);
}
export default Properties

You have to deal with your file input <input type="file"... differently to normal text fields. File inputs react differently to normal fields. They take an on change event, which updates when a user selects a file, and converts to a blob. You need to convert this to base64 and then send the base64 to the server (or a proper image hosting service such as cloudinary).
Here's a demo:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="file" id='file'/>
<script src='./app.js'></script>
</body>
</html>
app.js
const fileReader = document.getElementById('file')
const getBase64 = (file) => {
return new Promise((resolve, reject) => {
const fr = new FileReader()
console.log(file instanceof Blob) // Should be true
fr.readAsDataURL(file)
fr.onerror = reject
fr.onload = function () {
resolve(fr.result)
}
})
}
fileReader.addEventListener('change', (e) => {
console.log(e.target.files[0])
getBase64(e.target.files[0]).then((res) => console.log(res) )
})
In the JS above, we are getting the file reader input as an element and setting an onChange event to it, which calls the getBase64 function. The getBase64 function returns a Promise, that is fulfilled after the file has been read. Inside that function, we create a new FileReader as fr, then call fr.readDataAsURL(file) which converts your file to base64, and then resolve it in fr.onload. You can then call the output of that using getBase64(file).then(res => doSomething(res)).
Create a directory with those 2 files, and then test out the functionality. When you select a file, you should see a really long string of characters (Base64), and this is what you should post to your image hosting service.
I believe you can post base64 to MongoDB, though it is not recommended.

Related

Can not load array from backend

After a search, I am sending the result to frontend in the form of array. But I am not being able to get that array in frontend using fetch. Through postman I am able to get the result from the backend but I am not able to get it in the frontend. In another file, I have set axios.post as well and exported from there and imported in frotend.
I am beginner so I might have written a bad code, any help will mean a lot.
In frontend :
class Hostel extends Component{
constructor (){
super();
this.state = {
country : '',
city : '',
category : '',
errors : {}
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({
errors: nextProps.errors
});
}
}
onChangeAddOptions = e => {
this.setState({ [e.target.id]: e.target.value });
};
addOption = e => {
e.preventDefault();
const newOption = {
country : this.state.country,
city : this.state.city,
category:this.state.category,
}
this.props.saveOptions(newOption,this.props.history);
};
getHostels = async ()=> {
console.log("getHostel function is called");
const response = await fetch('http://localhost:5000/api/users/hostel',{
method : "POST",
// headers:{
// "Content-Type" : "application/json"
// },
})
.then((response)=> {response.json()})
.then((data)=>{
console.log("inside data");
console.log(data);
})
.catch(e=>{
console.error(e.error);
})
console.log("From outside of data");
console.log(response);
}
componentDidMount(){
this.getHostels();
}
render (){
const {errors,country,city,category} = this.state;
return(
<section className="Hosteldashboard">
<div className="left_container">
<h2>Yo che left section</h2>
<div>
<form noValidate onSubmit={this.addOption}>
<div class="form-row">
<label htmlFor="country">Country</label> <br />
<input
type="text"
className="input-control"
placeholder="Country name"
id="country"
value={country}
onChange={this.onChangeAddOptions}
error={errors.country}
className={classnames('', {
invalid: errors.country
})}
/>{' '}
<br />
<span className="text-danger">{errors.country}</span>
</div>
<div class="form-row">
<label htmlFor="city">City</label> <br />
<input
type="text"
className="input-control"
placeholder="City name"
id="city"
value={city}
onChange={this.onChangeAddOptions}
error={errors.city}
className={classnames('', {
invalid: errors.city
})}
/>{' '}
<br />
<span className="text-danger">{errors.city}</span>
</div>
<div class="form-row">
<label htmlFor="category">Category</label> <br />
<input
type="text"
className="input-control"
placeholder="Boys or Girls"
id="category"
value={category}
onChange={this.onChangeAddOptions}
error={errors.category}
className={classnames('', {
invalid: errors.category
})}
/>{' '}
<br />
<span className="text-danger">{errors.category}</span>
</div>
<div>
<button type="submit" className = "searchHostel" onClick={this.getHostels}>
Search
</button>
</div>
</form>
</div>
</div>
In backend :
router.post('/hostel',async (req,res)=>{
try{
console.log(req.body);
const {
errors,
isValid
} = validateSearchHostelInput(req.body);
//Check Validation
// if (!isValid){
// return res.status(400).json(errors);
// }
const page = parseInt(req.query.page) - 1 || 0;
const limit = parseInt(req.query.limit) || 5;
const search = req.query.search || "";
let sort = req.query.sort || "price";
let category = req.query.category || "All";
const categoryOptions = [
req.body.country,
req.body.city,
req.body.category
]
category === "All"
? (category = [...categoryOptions])
: (category = req.query.category.split(","));
req.query.sort ? (sort = req.query.sort.split(",")) : (sort = [sort]);
let sortBy = {};
if(sort[1]) {
sortBy[sort[0]] = sort[1];
} else {
sortBy[sort[0]] = "asc";
}
const hostel = await Hostel.find({title: {$regex: search, $options: "i"}})
.where("category")
.in([...category])
.sort(sortBy)
.skip(page * limit)
.limit(limit);
// const total = await Hostel.countDocuments({
// category: {$in: [...category]},
// title: { $regex: search, $options: "i"},
// });
// const response = {
// error: false,
// total,
// page: page + 1,
// limit,
// categories: categoryOptions,
// hostel
//}
console.log("From Hostel : " + hostel);
res.status(200).json({hostel:hostel});
}catch(err){
console.log(err);
res.status(500).json({error:true,message:"Internal Server Error"});
}
});
module.exports = router;

Unable to upload ( image + user data ) from react to node.js backend

When i click the register button then the REGISTER_USER function is called and then it creates a form obj with all the data and post it to the backend . i don't know why it is giving 500 error , cors error even tough i added cors in my app.js (node.js file)
Please help me with this issue ! Thanks in advance ...
Error
This is my backend Code
This implementsthe upload file and the user data to the data base
const imageStorage = multer.diskStorage({
destination: "./assets/images/Customers",
filename: (req, file, cb) => {
cb(
null,
file.originalname.split(".")[0] +
"-" +
Date.now() +
"." +
file.originalname.split(".")[1]
);
},
});
const upload_image = multer({
storage: imageStorage,
limits: {
fileSize: 10000000,
},
fileFilter(req, file, cb) {
if (!file.originalname.match(/\.(png|jpg)$/)) {
return cb(new Error("Only Png / Jpg format is accepted"));
}
cb(undefined, true);
},
});
router.post("/create-user", upload_image.single("image") , async (req, res) => {
try{
console.log(req.body)
console.log(req.file.filename)
let isPresent = await User.findOne({Name : req.body.Email.toLowerCase()})
if(isPresent !== null){
return res.status(400).json({ success : false , message : "Customer already present in the data base!"})
}else{
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.Password , salt)
let data = {...req.body , Name : req.body.Name.toLowerCase() , Password : hashedPassword , Email : req.body.Email.toLowerCase() , ProfilePic : req.file.filename};
console.log(data)
let Created_Customer = await User.create(data)
return res.status(200).json({success : true , message : "Successfully created the customer!" , Customer : Created_Customer});
}
}catch(err){
return res.status(500).json({success : false , message : err});
}
});
This is my FrontEnd Form Code
Function that post the data
const [adminData , setAdminData] = useState({
Name : "" ,
Email : "",
Password : "",
Role : "admin",
file : ""
})
const REGISTER_USER = async (e) =>{
e.preventDefault()
const formData = new FormData()
formData.append("Name" , adminData.Name)
formData.append("Email" , adminData.Email)
formData.append("Role" , adminData.Role)
formData.append("Password" , adminData.Password)
formData.append("image" , adminData.file)
const res = await fetch("http://localhost:5000/api/create-user" , {
method : "POST",
body : formData
})
console.log(res)
}
form
<form onSubmit={REGISTER_USER}>
<div>
<span>Name</span>
<span>
<input type="text" name ="Name" value ={adminData.Name} onChange={(e) => setAdminData({...adminData , [e.target.name] : e.target.value})}/>
<PersonOutlineRoundedIcon/>
</span>
</div>
<div>
<span>Email</span>
<span>
<input type="text" name ="Email" value ={adminData.Email} onChange={(e) => setAdminData({...adminData , [e.target.name] : e.target.value})}/>
<PersonOutlineRoundedIcon/>
</span>
</div>
<div >
<span>Password</span>
<span >
<input type="password" name ="Password" value ={adminData.Password} onChange={(e) => setAdminData({...adminData , [e.target.name] : e.target.value})}/>
<VisibilityOutlinedIcon />
</span>
</div>
<span>
<input type="file" name ="file" value ={adminData.file} onChange={(e) => setAdminData({...adminData , [e.target.name] : e.target.value})}/>
</span>
<button type="submit">
<span>Register</span>
<ArrowForwardOutlinedIcon/>
</button>
</form>
Data is recieved in this format at the backend

Unable to signup once login detail have been entered

I'm pretty new to React & node.js , and have attempted to create a chat messaging app. However im unable to access the rest of my app as every-time i sign in there is an error stating:
**Uncaught (in promise) Error: Request failed with status code 404
at createError (createError.js:16:1)
at settle (settle.js:17:1)
at XMLHttpRequest.onloadend (xhr.js:66:1)**
Auth.jsx file in client server
import React, {useState} from 'react';
import Cookies from 'universal-cookie';
import axios from 'axios';
import signinImage from '../assets/Group 2.png';
const cookies = new Cookies();
//forming the inital state of input fields
const initialState = {
fullName:'',
username:'',
password:'',
confirmPassword:'',
phoneNumber:'',
avatarURL:'',
}
const Auth = () => {
const [form, setForm] = useState(initialState);
const [isSignup , setIsSignup] = useState(true);
const handleChange = (e) => {
setForm({...form,[e.target.name]: e.target.value});
}
const handleSubmit = async (e)=>{
e.preventDefault();
const {username , password , phoneNumber , avatarURL } = form;
const URL = 'http://localhost:5009/auth'
//making requests to different url backened each time
const {data : { token ,userId , hashedPassword , fullName }} = await axios.post(`${URL}/${isSignup ? 'Sign Up ' : 'Sign In'}`,{
username , password , fullName: form.fullName , phoneNumber , avatarURL,
})
//storing data in cookies
cookies.set('token ' , token )
cookies.set('username ' , username )
cookies.set('fullName' , fullName)
cookies.set('userId ' , userId )
if (isSignup){
cookies.set('phoneNumber' , phoneNumber )
cookies.set('avatarURL' , avatarURL)
cookies.set('hashedPassword' , hashedPassword )
}
//reloads application
window.location.reload();
}
//changing state of my sign up screen depending on the state before
const switchMode = () => {
setIsSignup((prevIsSignup) => !prevIsSignup);
}
return (
<div className=" auth__form-container">
<div className="auth__form-container_fields">
<div className="auth__form-container_fields-content">
<p>{isSignup ? 'Sign up' : 'Sign In'}</p>
<form onSubmit= {handleSubmit}>
{isSignup &&(
<div className= "auth__form-container_fields-content_input">
<label htmlFor="fullName">Full Name</label>
<input
name="fullName"
type="text"
placeHolder= "Full Name"
onChange={handleChange}
required
/>
</div>
) }
<div className= "auth__form-container_fields-content_input">
<label htmlFor="username">Username</label>
<input
name="username"
type="text"
placeHolder= "Username"
onChange={handleChange}
required
/>
</div>
{isSignup &&(
<div className= "auth__form-container_fields-content_input">
<label htmlFor="phoneNumber">Phone Number</label>
<input
name="phoneNumber"
type="text"
placeHolder= "Phone Number"
onChange={handleChange}
required
/>
</div>
) }
{isSignup &&(
<div className= "auth__form-container_fields-content_input">
<label htmlFor="avatarURL">Avatar URL</label>
<input
name="avatarURL"
type="text"
placeHolder= "Avatar URL"
onChange={handleChange}
required
/>
</div>
) }
<div className= "auth__form-container_fields-content_input">
<label htmlFor="password">Password</label>
<input
name="password"
type="password"
placeHolder= "Password"
onChange={handleChange}
required
/>
</div>
{isSignup &&(
<div className= "auth__form-container_fields-content_input">
<label htmlFor="confirmPassword">Confirm Password</label>
<input
name="confirmPassword"
type="password"
placeHolder= "Confirm Password"
onChange={handleChange}
required
/>
</div>
) }
<div className="auth__form-container_fields-content_button">
<button>{isSignup ? "Sign up " : "Sign In"}</button>
</div>
</form>
<div className="auth__form-container_fields-account">
<p>
{isSignup
? "Already have an account?"
:"Dont have an account ?"
}
<span onClick={switchMode}>
{isSignup ? ' Sign In' : ' Sign up'}
</span>
</p>
</div>
</div>
</div>
<div className="auth__form-container_image">
<img src = {signinImage} alt ="Sign In" />
</div>
</div>
)
}
export default Auth
Below is the code for files in my server folder :
index.js
const express = require ('express');
const cors = require ('cors');
//adding routes for sign in + registrationn//
const authRoutes = require("./routes/auth.js");
const app = express ();
const PORT = process.env.PORT || 5009;
require ('dotenv').config();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded());
app.get('/' , (req,res) => {
res.send('ne, world');
});
app.use('/auth', authRoutes);
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Auth.js file in Controllers folder:
const { connect } = require('getstream');
const bcrypt = require('bcrypt');
const StreamChat = require('stream-chat').StreamChat;
const crypto = require('crypto');
require('dotenv').config();
const api_key = process.env.STREAM_API_KEY;
const api_secret = process.env.STREAM_API_SECRET;
const app_id = process.env.STREAM_APP_ID;
const signup = async (req, res) => {
try {
const { fullName, username, password, phoneNumber } = req.body;
const userId = crypto.randomBytes(16).toString('hex');
const serverClient = connect(api_key, api_secret, app_id);
const hashedPassword = await bcrypt.hash(password, 10);
const token = serverClient.createUserToken(userId);
res.status(200).json({ token, fullName, username, userId, hashedPassword, phoneNumber });
} catch (error) {
console.log(error);
res.status(500).json({ message: error });
}
};
const login = async (req, res) => {
try {
const { username, password } = req.body;
const serverClient = connect(api_key, api_secret, app_id);
const client = StreamChat.getInstance(api_key, api_secret);
const { users } = await client.queryUsers({ name: username });
if(!users.length) return res.status(400).json({ message: 'User not found' });
const success = await bcrypt.compare(password, users[0].hashedPassword);
const token = serverClient.createUserToken(users[0].id);
if(success) {
res.status(200).json({ token, fullName: users[0].fullName, username, userId: users[0].id});
} else {
res.status(500).json({ message: 'Incorrect password' });
}
} catch (error) {ads
console.log(error);
res.status(500).json({ message: error });
}
};
module.exports = { signup, login }
Auth.js file in routes folder
const express = require ('express');
const { signup, login } = require('../controllers/auth.js');
const router = express.Router();
//initialising my 2 different routes //
//post route sending data from frontend to backend
router.post('/signup', signup);
router.post('/login', login);
module.exports = router;
Any thought on what im doing wrong or can implement to change these errors would be much appreciated !

Cannot read property 'create' of undefined error when integrating Shippo

I am working on a product using node.js in my backend and react.js in my frontend. In this project, I am trying to integrate Shippo. They provide api information for the backend, which I have tried to use/follow. I am currently getting a cannot read property 'create' of undefined error, which is a POST 500 Internal Server Error from the backend, but I an unsure why I am getting this error and if I am integrating this system correctly. I would really appreciate any help or advice on what I could be doing wrong. Thank you!
Backend:
Shippo.js
'use strict';
import express from 'express';
import shippo from 'shippo';
const shippoToken = process.env.SHIPPO_TOKEN || ''
const shippoRouter = express.Router();
shippoRouter.post(
'/shippinginfo',
function (req, res) {
var addressFrom = {
"name": "Jane Smith",
"street1": "500 Riveride Dr",
"city": "New York",
"state": "NY",
"zip": "10002",
"country": "US"
};
const to = req.body
var addressTo = shippo.address.create({
"name": to.fullName,
"street1": to.address1,
"street2": to.address2,
"city": to.city,
"state": to.state,
"zip": to.postalCode,
"country": to.country,
"phone": to.phoneNumber,
"email":to.email,
"validate": true,
}, function(err, address) {
// asynchronously called
});
// asynchronously called
console.log(addressFrom)
console.log(addressTo)
var parcel = {
"length": "5",
"width": "5",
"height": "5",
"distance_unit": "in",
"weight": "2",
"mass_unit": "lb"
};
/*
shippo.shipment.create({
"address_from": addressFrom,
"address_to": addressTo,
"parcels": [parcel],
"async": false
}, function(err, shipment){
// asynchronously called
});
shippo.shipment.rates('5e40ead7cffe4cc1ad45108696162e42');
//var rate = shipment.rates[0];
// Purchase the desired rate.
shippo.transaction.create({
"rate": rate.object_id,
"label_file_type": "PDF_4x6",
"async": false
}, function(err, transaction) {
// asynchronous callback
});*/
});
export default shippoRouter;
server.js
import express from 'express';
import cors from 'cors';
import mongoose from 'mongoose';
import dotenv from 'dotenv';
import path from 'path';
import shippoRouter from './shippo.js';
dotenv.config();
const app = express();
app.use(cors()); //and this
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
mongoose.connect(process.env.MONGODB_URL || 'mongodb://localhost/AM', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
});
app.use('/api/shippo', shippoRouter);
app.get('/', (req, res) => {
res.send('Server is ready');
});
app.use((err, req, res, next) => {
res.status(500).send({ message: err.message });
});
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log(`Serve at http://localhost:${port}`);
});
How I tried to get the shipping information from my frontend using axios
Frontend:
ShippingAddressScreen.js
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { saveShippingAddress } from '../actions/cartActions';
import CheckoutSteps from '../components/CheckoutSteps';
import { shippingInfo } from '../actions/shippingActions';
export default function ShippingAddressScreen(props) {
const userSignin = useSelector((state) => state.userSignin);
const { userInfo } = userSignin;
const cart = useSelector((state) => state.cart);
const { shippingAddress } = cart;
if (!userInfo) {
props.history.push('/signin');
}
const [fullName, setFullName] = useState(shippingAddress.fullName);
const [address1, setAddress1] = useState(shippingAddress.address1);
const [address2, setAddress2] = useState(shippingAddress.address2);
const [city, setCity] = useState(shippingAddress.city);
const [state, setState] = useState(shippingAddress.state);
const [postalCode, setPostalCode] = useState(shippingAddress.postalCode);
const [country, setCountry] = useState(shippingAddress.country);
const [phoneNumber, setPhoneNumber] = useState('');
const [email, setEmail] = useState('');
const name = fullName;
const street1 = address1;
const street2 = address2;
const zip = postalCode;
const phone = phoneNumber;
const dispatch = useDispatch();
const submitHandler = (e) => {
e.preventDefault();
dispatch(
saveShippingAddress({ fullName, address1, address2, city, state, postalCode, country })
);
props.history.push('/payment');
dispatch(
shippingInfo({ name, street1, street2, city, state, zip, country, phone, email })
);
};
/* const shippingInfo = (e) => {
e.preventDefault();
};*/
return (
<div>
<CheckoutSteps step1 step2></CheckoutSteps>
<form className="form" onSubmit={submitHandler}>
<div>
<h1>Shipping Address</h1>
</div>
<div>
<label htmlFor="fullName">Full Name</label>
<input
type="text"
id="fullName"
placeholder="Enter full name"
value={fullName}
onChange={(e) => setFullName(e.target.value)}
required
></input>
</div>
<div>
<label htmlFor="address1">Address</label>
<input
type="text"
id="address1"
placeholder="Enter address"
value={address1}
onChange={(e) => setAddress1(e.target.value)}
required
></input>
</div>
<div>
<label htmlFor="address2">Address</label>
<input
type="text"
id="address2"
placeholder="Enter address"
value={address2}
onChange={(e) => setAddress2(e.target.value)}
></input>
</div>
<div>
<label htmlFor="city">City</label>
<input
type="text"
id="city"
name="city"
placeholder="Enter city"
value={city}
onChange={(e) => setCity(e.target.value)}
required
></input>
</div>
<div>
<label htmlFor="state">State</label>
<input
type="text"
id="state"
placeholder="Enter state"
value={state}
onChange={(e) => setState(e.target.value)}
required
></input>
</div>
<div>
<label htmlFor="postalCode">Postal Code</label>
<input
type="text"
id="postalCode"
placeholder="Enter postal code"
value={postalCode}
onChange={(e) => setPostalCode(e.target.value)}
required
></input>
</div>
<div>
<label htmlFor="country">Country</label>
<input
type="text"
id="country"
placeholder="Enter country"
value={country}
onChange={(e) => setCountry(e.target.value)}
required
></input>
</div>
<div>
<label htmlFor="phoneNumber">Phone Number</label>
<input
type="text"
id="phoneNumber"
placeholder="Enter Phone Number"
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value)}
required
></input>
</div>
<div>
<label htmlFor="email">Email</label>
<input
type="text"
id="email"
placeholder="Enter Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
></input>
</div>
<div>
<button className="primary" type="submit">
Continue
</button>
</div>
</form>
</div>
);
}
ShippingActions.js
import Axios from 'axios';
import {
SHIPPING_ADDRESS_FAIL,
SHIPPING_ADDRESS_REQUEST,
SHIPPING_ADDRESS_SUCCESS,
} from '../constants/shippingConstants';
export const shippingInfo = (name, street1, street2, city, state, zip, country, phone, email) => async (dispatch) => {
dispatch({ type: SHIPPING_ADDRESS_REQUEST, payload: { name, email} });
try {
const { data } = await Axios.post('/api/shippo/shippinginfo', {
name,
street1,
street2,
city,
state,
zip,
country,
phone,
email,
});
dispatch({ type: SHIPPING_ADDRESS_SUCCESS, payload: data });
} catch (error) {
dispatch({
type: SHIPPING_ADDRESS_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
I also have a shippingReducer, shippingConstants, and included the reducer in my store.js.
Also, if this is helpful https://goshippo.com/docs/reference/js#overview is Shippo's Api Information.
I am currently getting a cannot read property 'create' of undefined error
From the code you shared, it looks like you are not initializing the shippo module correctly in Shippo.js, therefore shippo.create method does not exist.
In your code, you are importing the shippo module, but not initializing it with the key:
import shippo from 'shippo';
const shippoToken = process.env.SHIPPO_TOKEN || ''
// <omitted>
var addressTo = shippo.address.create({
// <omitted>
Note that shippoToken remains unused in your file.
In the Shippo library documentation, they have the following example:
var shippo = require('shippo')('<YOUR_PRIVATE_KEY>');
Since you are using ES modules, you can't use this one-liner, so try something like this instead:
import shippo from 'shippo';
const shippoToken = process.env.SHIPPO_TOKEN || ''
// initialize the shippo constructor with token:
const shippoClient = shippo(shippoToken);
// now you can use shippoClient instead of shippo:
var addressTo = shippoClient.address.create({
// <omitted>

how to solve this Cannot POST error in MERN?

I am inserting two images along with the form data into MongoDB database.
While both images are stored in my pc folder but all form data isn't uploading in the database.
error
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /</pre>
</body>
</html>
in my console. Please help me how to solve that.
I have tried some previously asked question in stackOF.
app.js
const express = require("express")
const app = express()
const cors = require('cors');
const env = require("dotenv")
const port = 5000
env.config({path: "../server/config.env"})
require("../server/db/conn")
app.use(cors());
app.use(express.json())
app.use(require("../server/router/auth"))
app.listen(port, (err) => {
if (err) {
return console.error(err);
}
return console.log(`server is listening on ${port}`);
});
module.exports = "conn"
register.js(frontend)
const Register = () => {
const [newUser, setNewUser] = useState({
school: "",
address: "",
photo: "",
photoone: ""
});
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("school", newUser.school);
formData.append("photo", newUser.photo);
formData.append("photoone", newUser.photoone)
formData.append("address", newUser.address);
axios({
method: "post",
url: "/teacher",
data: formData,
headers: { "Content-Type": "multipart/form-data" },
})
.then((response) => {
console.log(response)
}).then((data) => {
console.log(data)
}).catch((error) => {
if (error.response) {
console.log(error.response.data)
}
})
};
const handleChange = (e) => {
setNewUser({ ...newUser, [e.target.name]: e.target.value });
};
const handlePhoto = (e) => {
setNewUser({ ...newUser, photo: e.target.files[0] });
};
const handlePhotoone = (e) => {
setNewUser({ ...newUser, photoone: e.target.files[0] });
};
return (
<>
<div className="container main">
<div className="row">
<div className="col-sm-6 col-md-6 col-lg-6">
<form onSubmit={handleSubmit} encType="multipart/form-data">
<div class="mb-3">
<label class="form-label">
Your school
</label>
<input
type="text"
class="form-control"
id="exampleInputPassword1"
id="school"
name="school"
value={newUser.school}
onChange={handleChange}
/>
</div>
<div class="input-group mb-3">
<input
type="file"
id="pic"
accept=".png, .jpg, .jpeg"
name="photo"
onChange={handlePhoto} type="file" class="form-control" id="inputGroupFile02" />
</div>
<div class="input-group mb-3">
<input
type="file"
id="pic"
placeholder="second photo"
accept=".png, .jpg, .jpeg"
name="photoone"
onChange={handlePhotoone} type="file" class="form-control" id="inputGroupFile01" />
</div>
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">
your address
</label>
<input
type="text"
id="address"
name="address"
value={newUser.address}
onChange={handleChange}
class="form-control"
aria-describedby="emailHelp"
/>
</div>
<button
value="register"
type="submit"
class="btn btn-primary"
>
Submit
</button>
</form>
</div>
</div>
</div>
</>
);
};
auth.js(backend)
const mongoose = require("mongoose")
const express = require("express")
const router = express()
require("../db/conn")
const User = require("../model/userSchema")
const Teacher = require("../model/userSchemaTeacher")
const multer = require('multer');
let path = require('path');
let fs = require("fs-extra");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
let schoolname = req.body.school;
let path = `C:/Users/kumar/Desktop/mern/server/images/${schoolname}`;
fs.mkdirsSync(path);
cb(null, path);
// cb(null, 'images');
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
const fileFilter = (req, file, cb) => {
const allowedFileTypes = ['image/jpeg', 'image/jpg', 'image/png'];
if (allowedFileTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(null, false);
}
}
let upload = multer({ storage, fileFilter });
router.route('/teacher').post(upload.fields([{
name: "photo", maxCount: 1
}, {
name: "photoone", maxCount: 1
}
])), (req, res) => {
const school = req.body.school;
const photo = req.file.filename
const photoone = req.file.filename
const address = req.body.address;
const newUserData = {
school,
photo,
photoone,
address,
}
const newUser = new Teacher(newUserData);
newUser.save()
.then(() => res.json('User Added'))
.catch((err) => {
console.log(err);
});
}
Please see how to solve that?
The route you are trying to POST your form data is not defined please set your route path like this:
router.post('/teacher',upload.fields([{
name: "photo", maxCount: 1
}, {
name: "photoone", maxCount: 1
}
]), (req, res) => {
const school = req.body.school;
const photo = req.files['photo'][0]
const photoone = req.files['photoone'][0]
const address = req.body.address;
const newUserData = {
school,
photo,
photoone,
address,
}
const newUser = new Teacher(newUserData);
newUser.save()
.then(() => res.json('User Added'))
.catch((err) => {
console.log(err);
});
})
...

Resources