I am trying to send data from front end to back end with react and nodejs. but when I console in front end it appear data but in backend it didn't get anything.
Here is my front end code:
const [imageSelected, setImageSelected] = useState("");
// Form submission
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData();
formData.append("file", imageSelected);
const payload = { title, mission, isSearchable, userId: currentUser.id };
formData.append("payload", payload);
// Send post request for signup
const res = await axios.post("/api/v1/teams/team", formData, {
headers: { "Content-type": "multipart/form-data" },
});
// If no validation errors were found
if (res.data.validationErrors === undefined) {
// Clear any errors
setErrorsArr([]);
// Hide the errors component
setShowErrors(false);
// Toggle the modal
toggleModal();
// Go to team management page
NextRouter.push(`/team/${res.data}`);
} else {
// Set errors
setErrorsArr(res.data.validationErrors.errors);
// Show the errors component
setShowErrors(true);
}
};
<input
type="file"
className="team--modal_upload_avatar"
ref={inputFile}
onChange={(e) => setImageSelected(e.target.files[0])}
/>
<Grid item xs={12} className={classes.avatarDiv}>
<Avatar
aria-label="team"
className={classes.avatar}
component="div"
onClick={onButtonClick}
>
<AddAPhotoIcon className={classes.avatarIcon} />
</Avatar>
Here is my route:
const express = require("express");
const router = express.Router();
const { catchErrors } = require("../errors/errorHandlers");
const { body, param } = require("express-validator");
const cloudinary = require("cloudinary").v2;
const path = require("path");
const Datauri = require("datauri/parser");
const cloud_name = process.env.CLOUDINARY_NAME;
const cloud_api_key = process.env.CLOUDINARY_API_KEY;
const cloud_api_secret = process.env.CLOUDINARY_API_SECRET;
const cloud_url = process.env.CLOUDINARY_URL;
cloudinary.config({
cloud_name: cloud_name,
api_key: cloud_api_key,
api_secret: cloud_api_secret,
cloudinary_url: cloud_url,
});
// Controller
const {
createTeam,
getUsersTeams,
getManagedTeams,
getTeamCredits,
getTeamData,
updateTeamData,
shutdownTeam,
checkTeamPermissions,
checkTeamPermissionsAndLimits,
addMember,
removeMember,
addMemberBackToTeam,
quitTeam,
} = require("./teamsController");
const {
checkUserVerification,
restrictedRoute,
checkData,
} = require("../helpers/apiHelpers");
router.post(
"/team",
(req, res) => {
console.log(res);
console.log("req body", req.body);
console.log("req files", req.files);
console.log("req user", req.user);
const dUri = new Datauri();
const dataUri = (req) =>
dUri.format(path.extname(req.name).toString(), req.data);
if (req.files !== undefined && req.files !== null) {
const { file, id } = req.files;
const newFile = dataUri(file).content;
cloudinary.uploader
.upload(newFile, {
folder: "TeamAvatar",
})
.then((result) => {
const imageUrl = result.url;
const data = { id: req.body.id, imageUrl };
createTeam(data);
return res
.status(200)
.json({ message: "Success", data: { imageUrl } });
})
.catch((err) =>
res.status(400).json({ message: "Error", data: { err } })
);
} else {
return res.status(400).json({ message: "Error" });
}
},
restrictedRoute,
[
body(
"title",
"Only alphabetical characters, numbers, and spaces are allowed."
)
.not()
.isEmpty()
.isLength({ min: 1, max: 25 })
.trim()
.matches(/^[a-zA-Z0-9 ]+$/)
.blacklist("\\<\\>\\;\\[\\]\\{\\}\\|\\%\\=\\(\\)\\~\\#")
.escape(),
body("mission", "Only alphabetical characters and spaces are allowed.")
.not()
.isEmpty()
.trim()
.blacklist("\\<\\>\\;\\[\\]\\{\\}\\|\\%\\=\\(\\)\\~\\#")
.escape(),
],
checkData,
catchErrors(checkUserVerification),
catchErrors(createTeam)
);
Here is my controller that have create team function:
exports.createTeam = async (req, res) => {
// Get the user id from the session
const userId = req.session.passport.user.id;
console.log("body", req.body);
console.log("files", req.files);
console.log("file", req.file);
// Make sure user has the credits to create a new team
const teamInfo = await models.User.findOne({
where: {
id: userId,
},
attributes: ["teamCredits"],
});
if (teamInfo.dataValues.teamCredits <= 0) {
res.status(200).json({
validationErrors: {
errors: [
{
msg: "You don't have any more team credits.",
},
],
},
});
return;
}
const { title, mission } = req.body;
// const { picture } = req.imageUrl;
// Make sure the user hasn't already created a team with that title.
const existingTeam = await models.Team.findOne({
where: {
title: title,
creatorId: userId,
},
});
if (existingTeam !== null) {
// Response and let the user know.
res.status(200).json({
validationErrors: {
errors: [
{
msg: "You already created a team with that name.",
},
],
},
});
return;
}
// Generator a public team id
const firstLetter = title[0];
const secondLetter = title[1];
const thirdLetter = title[2];
const timePart = Date.now();
const generatedPublicId = `${firstLetter}${secondLetter}${thirdLetter}${timePart}`;
const roomEntry = {
name: title,
status: true,
};
const roomResponse = await models.Room.create({ ...roomEntry });
const defaultTeamValues = {
title: title,
type: "simple team",
mission: mission,
// picture: picture,
agreement: "default",
inputs: "",
outputs: "",
duration_in_months: 12,
status: "Seeking new members",
public_team_id: generatedPublicId,
mergedTo: null,
creatorId: userId,
date_closed: null,
current_members_count: 1,
current_invites_count: 0,
max_team_members_allowed: 10,
max_invites_allowed: 20,
roomID: roomResponse.dataValues.id,
};
// No existing team was found with that title and created by that user.
// Create team.
const team = await models.Team.create(defaultTeamValues);
const defaultRoleValues = {
title: "creator",
duties: "",
rights: "all",
};
// Create role for new team
const role = await models.Role.create(defaultRoleValues);
const defaultMembershipValues = {
interests: "",
contributions: "",
authorization: "creator",
status: "active",
application_letter: "",
date_applied: Sequelize.literal("CURRENT_TIMESTAMP"),
date_joined: Sequelize.literal("CURRENT_TIMESTAMP"),
date_departed: null,
memberId: userId,
teamId: team.dataValues.id,
roleId: role.dataValues.id,
};
// Create membership for team with role and team ids
await models.Membership.create(defaultMembershipValues);
const newCreditValue = teamInfo.dataValues.teamCredits - 1;
// Update team credits the user has.
await models.User.update(
{ teamCredits: newCreditValue },
{
where: {
id: userId,
},
}
);
// Done
res.status(200).json(team.dataValues.public_team_id);
};
Why my back end didn't get any data I sent from front end to back end?
Add files
server.js:
/* eslint-disable no-undef */
const express = require("express");
const next = require("next");
const dotenv = require("dotenv");
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
const compression = require("compression");
const bodyParser = require("body-parser");
const logger = require("morgan");
const session = require("express-session");
const SequelizeStore = require("connect-session-sequelize")(session.Store);
const passport = require("passport");
const helmet = require("helmet");
const sslRedirect = require("heroku-ssl-redirect");
const socketIo = require("socket.io");
const http = require("http");
const {
saveMessage,
getAllMessagedByRoomID,
} = require("./services/chat/chatController");
// Setup Next.js then run express.
app.prepare().then(() => {
// Setup express
const server = express();
const chatServer = http.createServer(server);
const io = socketIo(chatServer);
// Socket Connection Start
io.on("connection", (socket) => {
chatID = socket.handshake.query.chatID;
socket.join(chatID);
//Send message to only a particular user
socket.on("send_message", (message) => {
saveMessage(message);
io.in(message.roomID).emit("receive_message", {
content: message.content,
roomID: message.roomID,
userID: message.userID,
});
});
socket.on("get_all_messages", async ({ roomID }) => {
const allMessagedByRoomID = await getAllMessagedByRoomID(roomID);
io.in(roomID).emit("send_all_messages", {
allMessagedByRoomID,
});
});
});
// Redirect all traffic to use ssl(https);
server.use(sslRedirect());
// Define PORT
const port = process.env.PORT || 3000;
let serverMode = "development";
// Check if node is setup for production
if (!dev) {
serverMode = "production";
}
if (serverMode === "production") {
server.use(helmet());
}
// Logger
server.use(
logger("dev", {
skip: function (req, res) {
return res.statusCode < 199; // Only log 400 and 500 codes
},
})
);
// Use body parser
server.use(bodyParser.urlencoded({ extended: false }));
server.use(bodyParser.json());
// Compression
server.use(compression());
// Database
const db = require("./models/index");
const sequelize = db.sequelize;
// Test db connection
sequelize
.authenticate()
.then(() => {
console.log("Database successfully connected!");
})
.catch((err) => {
throw new Error(err);
});
// Sessions Setup
const sessionMaxTime = 1000 * 60 * 60 * 24 * 5; // 5 Days
// Session options
const theSession = {
secret: process.env.SECRET,
name: "sessId",
resave: false,
saveUninitialized: false,
cookie: {
maxAge: sessionMaxTime,
sameSite: true,
},
store: new SequelizeStore({
db: sequelize,
table: "Session",
}),
};
// Session production options
if (serverMode === "production") {
server.set("trust proxy", 1); // Trust first proxy
theSession.cookie.secure = true; // Serve cookies on HTTPS only
}
server.use(session(theSession));
// Passport Setup
// require("./config/passport")(passport);
require("./config/passport");
server.use(passport.initialize());
server.use(passport.session());
// API Routes
const userRoutes = require("./services/users/usersAPI");
server.use("/api/v1/users", userRoutes);
const profileRoutes = require("./services/profiles/profilesAPI");
server.use("/api/v1/profiles", profileRoutes);
const teamRoutes = require("./services/teams/teamsAPI");
server.use("/api/v1/teams", teamRoutes);
const searchRoutes = require("./services/searches/searchAPI");
server.use("/api/v1/search", searchRoutes);
const ratingRoutes = require("./services/ratings/ratingsAPI");
server.use("/api/v1/ratings", ratingRoutes);
const inviteRoutes = require("./services/invites/invitesAPI");
server.use("/api/v1/invites", inviteRoutes);
const feedbackRoutes = require("./services/feedback/feedbackAPI");
server.use("/api/v1/feedback", feedbackRoutes);
const couponRoutes = require("./services/coupons/couponsAPI");
server.use("/api/v1/coupons", couponRoutes);
const chatRoutes = require("./services/chat/chatAPI");
server.use("/api/v1/chat", chatRoutes);
// Restricted Pages
const restrictedRoutes = require("./services/restricted/restrictedAPI");
server.use(restrictedRoutes);
// Run server
sequelize.sync({ force: true }).then(() => {
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Ready in ${serverMode} mode.`);
});
});
});
To handle HTTP POST requests in Express.js version 4 and above, you need to install the middleware module called body-parser.
body-parser extracts the entire body portion of an incoming request stream and exposes it on req.body.
const express = require('express')
const app = express()
const bodyParser = require('body-parser');
// support parsing of application/json type post data
app.use(bodyParser.json());
//support parsing of application/x-www-form-urlencoded post data
app.use(bodyParser.urlencoded({ extended: true }));
router.post("/team", (req, res) => {...})
In Addition:
To handle multipart/form-data request that support file upload, you
need to use multer multer module.
Basic usage example:
Don't forget the enctype="multipart/form-data" in your form.
<form action="/profile" method="post" enctype="multipart/form-data">
<input type="file" name="avatar" />
</form>
var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
var cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
// req.files is an object (String -> Array) where fieldname is the key, and the value is array of files
//
// e.g.
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body will contain the text fields, if there were any
})
In your case: route.js
const express = require("express");
const app = express();
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const router = express.Router();
const { catchErrors } = require("../errors/errorHandlers");
const { body, param } = require("express-validator");
const cloudinary = require("cloudinary").v2;
const path = require("path");
const Datauri = require("datauri/parser");
const cloud_name = process.env.CLOUDINARY_NAME;
const cloud_api_key = process.env.CLOUDINARY_API_KEY;
const cloud_api_secret = process.env.CLOUDINARY_API_SECRET;
const cloud_url = process.env.CLOUDINARY_URL;
cloudinary.config({
cloud_name: cloud_name,
api_key: cloud_api_key,
api_secret: cloud_api_secret,
cloudinary_url: cloud_url,
});
// Controller
const {
createTeam,
getUsersTeams,
getManagedTeams,
getTeamCredits,
getTeamData,
updateTeamData,
shutdownTeam,
checkTeamPermissions,
checkTeamPermissionsAndLimits,
addMember,
removeMember,
addMemberBackToTeam,
quitTeam,
} = require("./teamsController");
const {
checkUserVerification,
restrictedRoute,
checkData,
} = require("../helpers/apiHelpers");
router.post(
"/team", upload.single('file'),
(req, res) => {
console.log(res);
// req.file is the `file` file
// req.body will hold the text fields, if there were any
console.log("req body", req.body);
console.log("req file", req.file);
console.log("req user", req.user);
const dUri = new Datauri();
const dataUri = (req) =>
dUri.format(path.extname(req.name).toString(), req.data);
if (req.files !== undefined && req.files !== null) {
const { file, id } = req.files;
const newFile = dataUri(file).content;
cloudinary.uploader
.upload(newFile, {
folder: "TeamAvatar",
})
.then((result) => {
const imageUrl = result.url;
const data = { id: req.body.id, imageUrl };
createTeam(data);
return res
.status(200)
.json({ message: "Success", data: { imageUrl } });
})
.catch((err) =>
res.status(400).json({ message: "Error", data: { err } })
);
} else {
return res.status(400).json({ message: "Error" });
}
},
restrictedRoute,
[
body(
"title",
"Only alphabetical characters, numbers, and spaces are allowed."
)
.not()
.isEmpty()
.isLength({ min: 1, max: 25 })
.trim()
.matches(/^[a-zA-Z0-9 ]+$/)
.blacklist("\\<\\>\\;\\[\\]\\{\\}\\|\\%\\=\\(\\)\\~\\#")
.escape(),
body("mission", "Only alphabetical characters and spaces are allowed.")
.not()
.isEmpty()
.trim()
.blacklist("\\<\\>\\;\\[\\]\\{\\}\\|\\%\\=\\(\\)\\~\\#")
.escape(),
],
checkData,
catchErrors(checkUserVerification),
catchErrors(createTeam)
);
Related
When trying to submit an audio file to backend from the front end im getting two errors error: Error: Unexpected end of form
error: uploading file: Error: Failed to upload audio file
im using form data to send an audio file on the front end and multer and gridfs on the backend. does anybody know why i am getting this error.
When trying to submit an audio file to backend from the front end im getting this error: Error: Unexpected end of form, im using form data to send an audio file on the front end and multer and gridfs on the backend. does anybody know why i am getting this error.
here is my app.js
import React, { useState } from 'react';
const App = () => {
const [selectedFile, setSelectedFile] = useState(null);
const handleFileChange = (event) => {
setSelectedFile(event.target.files[0]);
}
const handleFormSubmit = (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('audioFile', selectedFile);
fetch('http://localhost:4002/audio', {
method: 'POST',
body: formData,
})
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Failed to upload audio file');
}
})
.then(data => {
console.log('File uploaded successfully:', data);
// Do something with the response data
})
.catch(error => {
console.error('Error uploading file:', error);
});
}
return (
<div className="flex h-[100vh] w-[100%] items-center justify-center">
<form onSubmit={handleFormSubmit} encType="multipart/form-data">
<input type="file" onChange={handleFileChange} />
<button type="submit" disabled={!selectedFile}>Upload</button>
</form>
</div>
);
};
export default App;
here is my sever.js
const express = require('express');
const mongoose = require('mongoose');
const multer = require('multer');
const { GridFsStorage } = require('multer-gridfs-storage');
const Grid = require('gridfs-stream');
const cors = require('cors');
const path = require('path')
const bodyParser = require("body-parser")
const app = express();
app.use(express.json());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
mongoose.connect('mongodb+srv://jordandeeds31:Jd400089#cluster0.ibeioeb.mongodb.net/?retryWrites=true&w=majority', {
useUnifiedTopology: true,
useNewUrlParser: true,
}).then(() => {
console.log('Connected to MongoDB');
}).catch((err) => {
console.error(err);
});
const conn = mongoose.connection;
let gfs;
conn.once('open', () => {
gfs = Grid(conn.db, mongoose.mongo);
gfs.collection('audioFiles');
});
const storage = new GridFsStorage({
url: 'mongodb+srv://jordandeeds31:Jd400089#cluster0.ibeioeb.mongodb.net/grid?retryWrites=true&w=majority',
file: (req, file) => {
return {
filename: file.originalname,
bucketName: 'audioFiles'
};
}
});
const upload = multer({
storage: storage,
limits: {
fileSize: 90 * 1024 * 1024 // 10MB
},
fileFilter: (req, file, cb) => {
if (file.mimetype.startsWith('audio/')) {
cb(null, true);
} else {
cb(new Error('File type not supported.'));
}
}
});
// Add this middleware before the POST route
app.use(upload.any());
const audioFileSchema = new mongoose.Schema({
fileUrl: {
type: String,
required: true
},
audioData: {
type: Buffer,
required: true
}
});
const AudioFile = mongoose.model('AudioFile', audioFileSchema);
app.post('/audio', upload.single('audioFile'), async (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ message: 'No file uploaded.' });
}
const audioFile = new AudioFile({
fileUrl: `http://localhost:4002/audio/${req.file.filename}`,
audioData: req.file.buffer
});
console.log('req.file.buffer:', req.file.buffer);
const savedAudioFile = await audioFile.save();
res.json({ fileUrl: savedAudioFile.fileUrl });
} catch (err) {
console.error(err);
if (err instanceof multer.MulterError) {
res.status(400).json({ message: 'File upload error.' });
} else if (err.message === 'File type not supported.') {
res.status(400).json({ message: err.message });
} else {
res.status(500).send('Internal Server Error');
}
}
});
app.get('/audio/:filename', (req, res) => {
const { filename } = req.params;
const readStream = gfs.createReadStream({ filename });
readStream.on('error', (err) => {
console.error(err);
res.status(404).send('File not found.');
});
readStream.pipe(res);
});
app.listen(4002, () => {
console.log('Listening on port 4002');
});
I already tried some possible solutions and even created and wrote the code again but I am still getting errors. I have created a diminute version of my whole code which connects to the database using Mongoose but after the Schema is created and I import the model in places-controllers my data that I write in POSTMAN goes directly to:
FYI: In this case I want POST request from createPlace to properly work.
Data entry: URL: http://localhost:5000/api/places/
{
"title": "Punta Arena Stfdsfdsfsdfop",
"description": "One stop Stop. Does not have tr12affic lights.",
"busrespect": "12ysdfdsfsfes",
"address": "Avenida Solunna",
"creator": "52peru soiflsdjf36"
}
OUTPUT:
{
"status": "error caught"
}
which is what I told the program to define if the try did not work.
IN app.js I have the following code:
const express= require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const placesRoutes = require("./routes/places-routes");
const HttpError = require ("./models/http-error");
const app = express();
app.use(bodyParser.json());
app.use('/api/places', placesRoutes);
app.use((req, res, next) => {
const error= new HttpError('Route not available. Try something different?', 404);
throw error;
});
app.use((error, req, res, next) =>{
if (res.headerSent) {
return next(error);
}
res.status(error.code || 500)
res.json({message: error.message || "An unknown error occured! Sorry" });
});
url = '<mongo_url>'
mongoose.connect(url, {useNewUrlParser: true}).then(()=>{
console.log("Connected to database")
app.listen(5000);
}).catch(erro => {
console.log(erro)
});
In places-routes.js I have the following code:
const express = require('express');
const {check} = require('express-validator')
const placesControllers=require('../controllers/places-controllers');
const router = express.Router();
router.get('/:pid', placesControllers.getPlaceById );
router.get('/user/:uid',placesControllers.getPlacesByCreatorId );
router.post('/' ,[
check('title')
.not()
.isEmpty(),
check('description').isLength({ min: 5 }),
check('address')
.not()
.isEmpty()
],
placesControllers.createPlace);
router.patch('/:pid', [
check('title')
.not()
.isEmpty(),
check('description').isLength({ min: 5 })
] , placesControllers.updatePlace );
router.delete('/:pid', placesControllers.deletePlace);
module.exports=router;
In places-controllers.js I have the following code:
const HttpError = require('../models/http-error');
const { validationResult } = require('express-validator');
//const getCoordsForAddress= require('../util/location');
const BusStop = require('../models/place');
let INITIAL_DATA = [
{
id: "p1",
title: "Samoa Stop",
description: "My first bus stop in Lima",
//location: {
// lat: 40.1382,
// lng:-23.23
// },
address: "Av. La Molina interseccion con calle Samoa",
busrespect: "yes",
creator: "u1"
}
];
const getPlaceById = (req, res, next) => {
const placeId = req.params.pid // Accessing the p1 in pid URL scrapping {pid:'p1'}
const place= INITIAL_DATA.find(p => { //find method goes over each element in the array, the argument p represents the element where find loop is
return p.id ===placeId
});
if (!place) {
const error= new HttpError('No bus stop found for the provided ID.', 404);
throw error;
}
res.json({place: place});
};
const getPlacesByCreatorId = (req, res, next)=> {
const userId = req.params.uid;
const places = INITIAL_DATA.filter(p=>{ //filter to retrieve multiple places, not only the first one
return p.creator ===userId;
});
if (!places || places.length===0) {
return next(
new HttpError('Could not find bus stops for the provide user id', 404)
);
}
res.json({places});
};
const createPlace = async (req, res,next) => {
const errors = validationResult(req);
if (!errors.isEmpty()){
return next(new HttpError ('Invalid bus stop please check your data', 422));
}
//const { title, description, busrespect, address, creator } = req.body; //erased location for now.
/* let place = new BusStop({
title: req.body.title,
description: req.body.description,
busrespect: req.body.busrespect,
address : req.body.address,
creator: req.body.creator
})
awaitplace.save()
.then(response=>{
res.json({
message : "Employee added sucessfully!"
})
})
.catch(err=>{
res.json({
message : "An error has occured!"
})
})
} */
const { title, description, busrespect, address, creator } = req.body;
try {
await BusStop.create({
title:title,
description: description,
busrespect:busrespect,
address: address,
creator: creator
});
res.send({status: "ok"});
} catch(error) {
res.send({status:"error caught"});
}
};
const updatePlace = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()){
console.log(errors);
throw new HttpError ("Invalid inputs passed, please check your data ", 422);
};
const { title, description } = req.body;
const placeId = req.params.pid;
const updatedPlace = { ...INITIAL_DATA.find(p => p.id === placeId)};
const placeIndex = INITIAL_DATA.findIndex(p => p.id === placeId);
updatedPlace.title = title;
updatedPlace.description = description;
INITIAL_DATA[placeIndex] = updatedPlace;
res.status(200).json({place: updatedPlace});
};
const deletePlace = (req, res, next) => {
const placeId = req.params.pid;
if (!INITIAL_DATA.find(p=> p.id ===placesId))
throw new HttpError('Could not find a bus stop for that ID ')
INITIAL_DATA = INITIAL_DATA.filter(p=> p.id !== placeId)
res.status(200).json({message: 'Deleted Place'});
};
exports.getPlaceById= getPlaceById;
exports.getPlacesByCreatorId = getPlacesByCreatorId;
exports.createPlace = createPlace;
exports.updatePlace = updatePlace;
exports.deletePlace = deletePlace;
Inside models folder I have two files: http-error.js which has this code:
class HttpError extends Error {
constructor(message, errorCode) {
super (message);
this.code = errorCode;
}
}
module.exports = HttpError;
The other file inside is the schema which is place.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const placeSchema = new Schema({
title: {
type: String
},
description: {
type: String
},
address: {
type: String
},
busrespect: {
type: String
},
creator: {
type: String
}
},
)
const BusStop = mongoose.model('BusStop', placeSchema)
module.exports= BusStop
Summary: somewhere in the try catch part from createPlace something is going wrong since my data entry is always going to the error status I indicated in that part.
I am testing my express router with axios post-call to backend. I am getting 500 responses instead of 200, not sure how to mock the multer effectively.
Any thoughts on this? Thanks
routes.jsx
const axios = require('axios')
const router = express.Router()
const multer = require('multer')
const FormData = require('form-data')
const express = require('express')
const upload = multer({ storage: multer.memoryStorage() }).any()
router.post('/', upload, (req, res) => {
const formData = new FormData()
const { body } = req
req.files.forEach(file => {
formData.append(
'files',
file.buffer,
{
filename: file.originalname
},
file.originalname
)
})
axios
.post('/api/endpoint', formData)
.then(response => {return response
})
.catch(e => {
console.log(e)
})
})
module.exports = router
Below are my test case
routes.jsx.test
const axios = require('axios')
const MockAdapter = require('axios-mock-adapter')
const myroute = require('myroute')
const app = express()
const mock = new MockAdapter(axios)
const request = require('supertest')
const express = require('express')
const bodyParser = require('body-parser')
const multer = require('multer')
jest.mock('multer')
multer.mockImplementation(() => {
return {
any () {
return (req, res, next) => {
req.body = { userName: 'testUser' }
req.files = [
{
originalname: 'sample.name',
mimetype: 'sample.type',
path: 'sample.url'
}
]
return next()
}
}
}
})
app.use(bodyParser.json())
app.use('/', myroute)
describe('sendFiles', () => {
const url = '/api/endpoint'
test('200 response', () => {
const myMockRes = { mykey: 'myVal' }
let formData = new FormData()
const file = new Blob(['somee contents'], { type: 'multipart/form-data' })
formData.append('files', file)
formData.append('userName', 'testUser')
mock.onPost(url).reply(200, myMockRes)
return (
request(app)
.post('/')
.send({ userName: 'testUser', files: [file] })
//.expect('Content-Type', /json/)
.expect(200)
.then(response => {
const { data } = response.body
expect(data).toEqual(myMockRes)
})
)
})
})
error:
TypeError: Cannot read property 'any' of undefined in routes.jsx
const upload = multer({ storage: multer.memoryStorage() }).any()
When you use jest.mock('multer'), Jest automatically mocks the module and returns undefined when it gets called in the test. Since we want to mock memoryStorage and any methods as well, we have to do it explicitly by passing a factory as the second argument to jest.mock.
jest.mock('multer', () => {
const multer = () => ({
any: () => {
return (req, res, next) => {
req.body = { userName: 'testUser' }
req.files = [
{
originalname: 'sample.name',
mimetype: 'sample.type',
path: 'sample.url',
buffer: Buffer.from('whatever'), // this is required since `formData` needs access to the buffer
},
]
return next()
}
},
})
multer.memoryStorage = () => jest.fn()
return multer
})
The other issue is that Blob does not exist in Node. You can use Buffer.from to generate a buffer to send in the request.
const file = Buffer.from('whatever')
And you don't need to use FormData in the test.
The whole code:
// router.test.js
const axios = require('axios')
const MockAdapter = require('axios-mock-adapter')
const express = require('express')
const app = express()
const mock = new MockAdapter(axios)
const request = require('supertest')
const bodyParser = require('body-parser')
const myroute = require('./router')
jest.mock('multer', () => {
const multer = () => ({
any: () => {
return (req, res, next) => {
req.body = { userName: 'testUser' }
req.files = [
{
originalname: 'sample.name',
mimetype: 'sample.type',
path: 'sample.url',
buffer: Buffer.from('whatever'),
},
]
return next()
}
},
})
multer.memoryStorage = () => jest.fn()
return multer
})
app.use(bodyParser.json())
app.use('/', myroute)
describe('sendFiles', () => {
const url = '/api/endpoint'
test('200 response', () => {
const myMockRes = { mykey: 'myVal' }
const file = Buffer.from('whatever')
mock.onPost(url).reply(200, myMockRes)
return request(app)
.post('/')
.send({ userName: 'testUser', files: [file] })
.expect(200)
.then((response) => {
const { data } = response.body
expect(data).toEqual(myMockRes)
})
})
})
#Arun Kumar Mohan got me halfway there. Good happy path. But what about the error path? Arun has it right. You need to mock this. But what about triggering error paths within the callback? Providing a jest function that you can trigger can get you into those error paths.
import { UploadGuard } from '../../../src/guards';
import { Request } from 'express';
// Note: make a spy to get into the guts of the thing.
let spy = jest.fn();
jest.mock('multer', () => {
const multer = () => ({
any: () => {
return (req, res, next) => {
// Note: have the spy execute in the next.
return next(spy());
};
},
});
multer.memoryStorage = () => jest.fn();
return multer;
});
describe('Upload Guard', () => {
let guard: UploadGuard;
const loggerService = new MockLogger();
// Note: Good practice, always reset your mocks.
afterEach(() => jest.resetAllMocks());
beforeEach(() => {
spy = jest.fn();
guard = new UploadGuard(loggerService);
});
it('Should set the files on a request', async () => {
// Given
const executionContext = {
switchToHttp: () => ({
getRequest: () =>
({
headers: {
authorization: 'Bearer FakeJWT',
Content-Type: 'multipart/form-data',
},
body: {},
} as Request),
}),
};
// When
await guard.canActivate(executionContext as any);
// Then
expect(spy).toHaveBeenCalled();
});
it('Throw an error if something bad happens', async () => {
// Given
spy.mockImplementationOnce(() => {
// Note: Return not throw
return new Error('Bad Things');
});
const executionContext = {
switchToHttp: () => ({
getRequest: () => ({} as Request),
}),
};
try {
// When
await guard.canActivate(executionContext as any);
throw new Error('Should not happen');
} catch (err) {
// Then
expect(err.message).toBe('Bad Things');
}
});
});
const Koa = require('koa');
const cors = require('#koa/cors');
var https = require('https');
var http = require('http');
const { default: enforceHttps } = require('koa-sslify');
const next = require('next');
const { default: createShopifyAuth } = require('#shopify/koa-shopify-auth');
const dotenv = require('dotenv');
const { verifyRequest } = require('#shopify/koa-shopify-auth');
const session = require('koa-session');
const { ApiVersion } = require('#shopify/koa-shopify-graphql-proxy');
const { default: graphQLProxy } = require('#shopify/koa-shopify-graphql-proxy');
dotenv.config();
const port = parseInt(process.env.PORT, 10) || 9000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const Router = require('koa-router');
const processPayment = require('./server/router');
const helloMessage = require('./server/router');
const { SHOPIFY_API_SECRET_KEY, SHOPIFY_API_KEY } = process.env;
const crypto = require('crypto');
const cookie = require('cookie');
const nonce = require('nonce')();
const querystring = require('querystring');
const request = require('request-promise');
var bodyParser = require('koa-bodyparser');
const apiKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx";
const apiSecret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const scopes = 'read_products,write_script_tags,read_script_tags,read_customers, write_customers,read_product_listings,read_orders';
const forwardingAddress = "https://qualzz.com:9000";
//const forwardingAddress = "https://18.188.232.26:9000"
const appInstallAddress = "https://qualzz.com/api/user/webhooks/userInStalledApp";
const createUserUrlLink = "https://qualzz.com/api/user/createUser";
const forgotPasswordUrl = "https://qualzz.com/api/user/forgotPassword";
var fs = require('fs');
var LocalStorage = require('node-localstorage').LocalStorage,
localStorage = new LocalStorage('./scratch');
var email = "";
//var key = fs.readFileSync('/etc/nginx/qualzz.com.key');
//var cert = fs.readFileSync('/etc/nginx/qualzz_ssl.crt');
//var credentials = {key: key, cert: cert};
//var httpsServer = https.createServer(credentials, Koa);
// httpsServer.listen(port,()=>{
// console.log(`> Ready on http://localhost:${port}`);
//});
app.prepare().then(() => {
console.log("Started")
const server = new Koa();
const router = new Router();
server.use(enforceHttps({
port: port
}));
server.use(cors());
server.use(bodyParser());
server.use(session(server));
server.keys = ["XXXXXXXXXXXXXXXXXXXXX"];
router.get('/', processPayment);
router.get('/hello', async (ctx) => {
ctx.body = {
status: 'success',
message: 'hello, world!'
};
})
module.exports = router;
router.get('/shopify', (ctx,next) => {
console.log("ctx -->",ctx.query)
const shop = ctx.query.shop;
if (shop) {
const state = nonce();
const redirectUri = forwardingAddress + '/shopify/callback';
const installUrl = 'https://' + shop +
'/admin/oauth/authorize?client_id=' + apiKey +
'&scope=' + scopes +
'&state=' + state +
'&redirect_uri=' + redirectUri;
ctx.cookies.set('state', state);
console.log("install url ---->",installUrl)
ctx.redirect(installUrl);
} else {
return ctx.status(400).send('Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request');
}
});
router.get('/shopify/callback', (ctx,next) => {
console.log("in ctx call",ctx.query);
const { shop, hmac, code, state } = ctx.query;
const stateCookie = cookie.parse(ctx.headers.cookie).state;
if (state !== stateCookie) {
return ctx.status(403).send('Request origin cannot be verified');
}
if (shop && hmac && code) {
const map = Object.assign({}, ctx.query);
delete map['signature'];
delete map['hmac'];
const message = querystring.stringify(map);
const providedHmac = Buffer.from(hmac, 'utf-8');
const generatedHash = Buffer.from(
crypto
.createHmac('sha256', apiSecret)
.update(message)
.digest('hex'),
'utf-8'
);
let hashEquals = false;
try {
hashEquals = crypto.timingSafeEqual(generatedHash, providedHmac)
} catch (e) {
hashEquals = false;
};
if (!hashEquals) {
return res.status(400).send('HMAC validation failed');
}
const accessTokenRequestUrl = 'https://' + shop + '/admin/oauth/access_token';
const accessTokenPayload = {
client_id: apiKey,
client_secret: apiSecret,
code,
};
// setTimeOut(()=>{
console.log("near to redirect"+email);
ctx.redirect('https://app.qualzz.com?email='+email);
// },500);
//ctx.redirect('http://www.google.com');
request.post(accessTokenRequestUrl, { json: accessTokenPayload })
.then((accessTokenResponse) => {
const accessToken = accessTokenResponse.access_token;
const createScriptTagUrl = 'https://'+shop+'/admin/script_tags.json';
const shopRequestHeaders = {
'X-Shopify-Access-Token': accessToken,
};
const scriptTagBody = {"script_tag":
{ "event": "onload",
"src": "https://app.qualzz.com/assets/trackingScript/webtracking.js"
}
};
var redirectUrl = 'https://app.qualzz.com?email='+email;
const shopRequestUrl = 'https://' + shop + '/admin/shop.json';
// const saveCustomerUrl = 'http://ec2-18-216-255-14.us-east-2.compute.amazonaws.com:8080/user/webhooks/userInStalledApp';
const saveCustomerUrl = appInstallAddress;
request.get(shopRequestUrl, { headers: shopRequestHeaders })
.then((shopResponse) => {
//script tag try 3
const shopDetail = {
"shop":{
"id":JSON.parse(shopResponse).shop.id,
"email":JSON.parse(shopResponse).shop.email,
"phone":JSON.parse(shopResponse).shop.phone,
"name":JSON.parse(shopResponse).shop.name,
"domain":JSON.parse(shopResponse).shop.domain
}
}
console.log(shopDetail.shop.domain+">>>>>>>>>>>>>>>>>>emailemailxxx<<<<<<<<");
email = shopDetail.shop.email+'&url='+shopDetail.shop.domain;
console.log(email);
const createUser = {
"email":JSON.parse(shopResponse).shop.email,
"fullName":JSON.parse(shopResponse).shop.name,
"password":'XXXXXXXXX',
"shopify":true
}
const createUserUrl = createUserUrlLink;
request.post({
url:saveCustomerUrl,
body:shopDetail,
json:true
},function(error,response,body){
if(!error){
console.log("success in saving"+error+response+body);
request.post({
url: createScriptTagUrl,
body: scriptTagBody,
headers: shopRequestHeaders,
json: true
}, function( error,response,body){
if (ctx) {
console.log("before route -->",redirectUrl)
console.log("ctxroute --->",ctx)
ctx.redirect(redirectUrl);
} else {
ctx.body = {
status:error.statusCode,
message:'error'
}
}
});
ctx.redirect('https://app.qualzz.com?email='+email);
}
})
.catch((error) => {
res.status(error.statusCode);
});
request.post({
url:createUserUrl,
body:createUser,
json:true
},function(error,response,body){
if(!error){
console.log("success in user creation");
}else{
console.log('Error in user creation',error)
}
})
.catch((error)=>{
// redirectSite();
ctx.body ={
status:error.statusCode,
message:'error'
}
})
})
.catch((error) => {
ctx.body = {
status:error.statusCode,
message:'error'
}
});
function redirectSite(){
server.use((ctx,next) => {
});
//script tag try 2
}
})
.catch((error) => {
ctx.body = {
status:error.statusCode,
message:'error'
}
});
} else {
res.status(400).send('Required parameters missing');
}
});
//var dummyObj;
var shopifyObject;
router.post('/shopify/plan/upgrade',async(ctx)=>{
console.log("ctx --->",ctx.request.body);
obj = ctx.request.body.plan;
shopifyObject = ctx.request.body.userInfo;
localStorage.setItem('shopifyObject',JSON.stringify(shopifyObject));
console.log("shopify object is --->",shopifyObject)
const upgradeUrl= ctx.request.body.url;
// ctx.redirect('/');
// ctx.redirect(upgradeUrl);
ctx.body = {
status:"200",
message:'success'
}
});
// console.log("shopiufy object--->",shopifyObject)
obj = {
name: 'Recurring charge',
price: 20.01,
return_url: "https://qualzz.com:9000",
test: true
}
//console.log("calling this ... ");
server.use(
createShopifyAuth({
apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
scopes: ['write_products', 'read_products'],
async afterAuth(ctx) {
const { shop, accessToken } = ctx.session;
console.log("Object is -->",obj);
// localStorage.setItem('shopifyObject', shopifyObject)
ctx.cookies.set('shopOrigin', shop, { httpOnly: false });
const stringifiedBillingParams = JSON.stringify({
recurring_application_charge: obj
})
console.log("in --->",obj)
const options = {
method: 'POST',
body: stringifiedBillingParams,
credentials: 'include',
headers: {
'X-Shopify-Access-Token': accessToken,
'Content-Type': 'application/json',
},
};
const confirmationURL = await fetch(
`https://${shop}/admin/api/2019-04/recurring_application_charges.json`, options)
.then((response) => response.json())
.then((jsonData) => jsonData.recurring_application_charge.confirmation_url)
.catch((error) => console.log('error', error));
console.log("Confirmation url",confirmationURL)
ctx.redirect('/');
ctx.redirect(confirmationURL);
},
}),
);
server.use(graphQLProxy({version: ApiVersion.April19}))
server.use(router.routes());
// server.use(cors());
server.use(verifyRequest({authRoute: '/shopify/auth', fallbackRoute: '/shopify/auth'}));
server.use(async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
return
});
var key = fs.readFileSync('/etc/nginx/qualzz.com.key');
var cert = fs.readFileSync('/etc/nginx/qualzz_ssl.crt');
var credentials = {key: key, cert: cert};
https.createServer(credentials, server.callback()).listen(port);
});
I have created Shopify app after installing app I want to take the user to my site with email and shop URL as param so as in above code I am redirecting user with email and URL but i am not able to get current user email and store url am getting previous user details so where can i write redirect code so that i will get proper result.
help me for this..
The correct use is as follows. Shopify merchant installs your App. Once they approve your App, the callback to your App comes with the shop name and a token allowing you access to the Shop details. Use an API call with that token to get the email address you need.
I'm attempting to save data from an API response and keep getting an empty object. I placed a console.log in my code and it shows that I'm getting a response from the api. I seem to be missing something after the fetch request.
From index.js:
const express = require('express')
const bodyParser = require('body-parser')
const path = require('path')
const fetch = require('node-fetch')
const exphbs = require('express-handlebars')
const db = require('./src/models/movie')
require('./src/db/mongoose')
const Movie = require('./src/models/movie')
const app = express()
const port = process.env.PORT || 3000
// APP CONFIG
app.use(express.json())
app.use(bodyParser.urlencoded({extended: true}))
// ROUTES - ADD
app.post('/movies/:imdbID', (req, res) => {
const imdb = req.params.imdbID
const url = `**api link and key**${imdb}`
const movie = fetch(url).then((res) => {
return res.json()
}).then((response) => {
console.log(response)
const addMovie = new Movie(response)
db.Movie.create(addMovie, (err, newMovie) => {
if(err){
res.render('movie404')
} else {
res.redirect('/')
}
})
}).catch((e) => {
res.status(500).send(e)
})
})
From mongoose.js:
const mongoose = require('mongoose')
mongoose.connect('mongodb://127.0.0.1:27017/movietime-api', {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
useFindAndModify: false
})
From details.handlebars:
<h2>{{details.Title}}</h2>
<img src="{{details.Poster}}" alt="{{details.Title}}">
<p><em>{{details.Plot}}</em></p>
<p>Starring: {{details.Actors}}</p>
<p>Director: {{details.Director}}</p>
<form action="/movies/{{details.imdbID}}" method="POST">
<button type="submit">Add</button>
</form>
From movie.js:
const mongoose = require("mongoose");
// MONGOOSE/MODEL CONFIG
const Movie = mongoose.model('Movie',{
imdbID: String,
Title: String,
Poster: String,
Director: String,
Year: String,
Plot: String,
Ratings: String,
Rated: String,
Genre: String,
Writer: String,
Actors: String
});
module.exports = Movie;
I would expect a redirect to the index page then a new database entry using the above model.
you are almost there just few thing needs to be taken care of:
app.post('/movies/:imdbID', (req, res) => {
const imdb = req.params.imdbID
const url = `**api link and key**${imdb}`
const movie = fetch(url).then((res) => {
return res.json()
}).then((response) => {
console.log(response)
const addMovie = new Movie(response)
addMovie.save((err, newMovie) => {
if(err){
res.render('movie404',newMovie) // to render the details
} else {
res.redirect('/')
}
})
}).catch((e) => {
res.status(500).send(e)
ref