Why is Data not being passed through my Node REST API? - javascript

I have the following code.
routes/index.js:
const express = require('express');
const router = express.Router();
const weeklyReportsController = require('../controllers/weeklyReportsController');
router.get('/weekly_reports', weeklyReportsController);
module.exports = router;
controllers/weeklyReportsController.js:
const weeklyReportsService = require('../services/weeklyReportsService');
const weeklyReportsController = async (req, res) => {
try {
const data = await weeklyReportsService;
res.json({data})
console.log('Weekly reports controller - success');
} catch(err) {
console.log(err);
}
};
module.exports = weeklyReportsController;
services/weeklyReportsService.js:
const Pool = require('pg').Pool
const pool = new Pool({connection data})
const weeklyReportsService = async () => {
const res = await pool.query('SELECT * FROM reports', (err, results) => {
if (err) {
throw err;
} else {
console.log('Weekly reports service - success.');
}
return res.status(200).json(results.rows);
});
};
module.exports = weeklyReportsService;
All I am returning by visiting localhost:8080/api/weekly_reports is an empty JSON object of {}. I tried adding some console.log() methods to my code to see what was triggering and what wasn't, and the log from my service is not being set off. I have spent a couple hours trying to dig through example codes, reading documentation, and honestly just looking blankly at my screen - I just can't figure out what I did wrong here.
Does anyone have a suggestion as to what I am doing wrong here?
Thank you all for your time and if there is anything I can add for clarity, please don't hesitate to ask and I will provide it.
Thank you for your help.
EDIT: The data is sitting in a Postgres database called reports with the table also called reports.

There are many things wrong with your approach
Here's how you can achieve what you're trying to do:
controllers/weeklyReportsController.js:
const weeklyReportsController = async (req, res) => {
try {
const data = await weeklyReportsService();
res.status(200).json({data})
console.log('Weekly reports controller - success');
} catch(err) {
console.log(err);
res.status(500).json({error: err.message})
}
};
module.exports = weeklyReportsController;
services/weeklyReportsService.js:
const Pool = require('pg').Pool
const pool = new Pool({connection data})
const weeklyReportsService = () => {
return new Promise((resolve,reject) => {
pool.query('SELECT * FROM reports', (err, results) => {
if (err) reject(err);
console.log('Weekly reports service - success.');
resolve(results.rows)
});
})
};
module.exports = weeklyReportsService;
some links to help you get started:
https://expressjs.com/en/api.html#res
https://developer.mozilla.org/en-US/docs/Glossary/Callback_function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://stackoverflow.com/a/64052334/2703813
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Related

Why mongoose is not awaiting for await new MODEL.save()

I have 2 servers and one of these is work fine, but second (modified variant of first) is not
`This is not works:
router.post("/", async (req, res, next) => {
const newBriefAppeal = await new BriefAppeal(req.body);
let appealId;
let target;
let goals;
let brand;
let ***;
try {
const savedBriefAppeal = await newBriefAppeal.save(function (err, appeal) {
appealId = appeal.id;
target = appeal.step01target;
goals = appeal.step02goals;
brand = appeal.step03brand;
*** = appeal.***
});
res.status(200).json(savedBriefAppeal);
} catch (err) {
res.status(500).json(err);
}
});
`
and i got error
node:events:491
throw er; // Unhandled 'error' event
^
TypeError: Cannot read properties of undefined (reading 'id')
`but this variant in my similar project works fine:
router.post("/", async (req, res, next) => {
const newAppeal = await new Appeal(req.body);
let appealId;
let name;
let email;
let phone;
let subject;
let message;
let attachments = [];
try {
const savedAppeal = await newAppeal.save(function (err, appeal) {
appealId = appeal.id;
name = appeal.name;
email = appeal.email;
phone = appeal.phone;
subject = appeal.subject;
message = appeal.text;
attachments = appeal.appealAttach.map((attachment) => ({
filename: attachment,
path: "./uploads/media/mailAttachments/" + attachment,
}));
});
res.status(200).json(savedAppeal);
} catch (err) {
res.status(500).json(err);
}
});
Where's i'm wrong and why my appeal is undefined ?
Because you're passing in a callback. As it says in the documentation, save only returns a promise when you don't pass in a callback:
Returns:
...Returns undefined if used with callback or a Promise otherwise.
Either use the old-style callback signature or use the promise feature.

Why does my program crash when managing this JSON file?

Whenever somebody sends !setmainchannel, my program crashes. I am using Node.js with the package discord.js. This is the only problem I have. I don't and can't understand what's wrong, and I would extremely appreciate it if someone could help me out.
bot.js:
let Discord = require("discord.js");
let client = new Discord.Client();
let fs = require('fs');
let help = require("./helpembed.json");
var jsonRead = function(filePath){
fs.readFile(filePath, 'utf-8', (err, returnJson) => {
if(err){
console.log(err);
}
else{
let ret = JSON.parse(returnJson);
return ret;
}
})
}
var jsonWrite = function(filePath, objIn){
fs.writeFile(filePath, JSON.stringify(objIn), err => {
if(err){
console.log(err);
}
})
}
client.on("message", msg => {
let time = new Date();
let cstTimeStamp = `${time.getMonth() + 1}/${time.getDate()}/${time.getFullYear()} ${time.getHours() + 1}:${time.getMinutes()}:${time.getSeconds()}`
if(msg.content == "!setmainchannel"){
let mainChannel = msg.mentions.channels.first();
if(!mainChannel){
console.log(`${cstTimeStamp} #${msg.author.tag} requested to set a main channel but didn't provide a channel\n`);
msg.channel.send("There's no channel to set the main to");
}
else{
let currentSettings = jsonRead("./main-channel.json");
currentSettings.channel = mainChannel;
jsonWrite("./main-channel.json", currentSettings);
console.log(`${cstTimeStamp} #${msg.author.tag} set the main channel as ${currentSettings.channel}\n`);
msg.channel.send(`Set the main channel as ${currentSettings.channel}`);
}
}
})
client.once('ready', () => {
console.log('Bot is online\n');
});
client.login('Token hidden for safety reasons');
main-channel.json:
{
"channel":null
}
First, your bot does nothing because it only reacts if (msg.content == "!setmainchannel"). If you provide an argument, like a channel (!setmainchannel #ch-name), it won't run as the message's content is not exactly the prefix and the command.
You'll need to fix that first. By removing the prefix and chopping off the arguments, you can get the command itself and check if this exact command is used. (Again, you should not check the whole message.content)
Second, you don't wait for the callback inside readFile to run. It means, when you try to update currentSettings.channel, your jsonRead() function has just started to read the file and the currentSettings is undefined. You won't be able to update its channel property.
I've updated both your jsonWrite and jsonRead functions to return promises and make it easier to use. Check the working code below:
const Discord = require("discord.js");
const fs = require('fs');
const path = require('path');
const client = new Discord.Client();
const prefix = '!';
client.on('message', async (msg) => {
// create an args variable that slices off the prefix and splits it into an array
const args = msg.content.slice(prefix.length).split(/ +/);
// create a command variable by taking the first element in the array
// and removing it from args
const command = args.shift().toLowerCase();
const cstTimeStamp = new Date().toLocaleString();
if (command === 'setmainchannel') {
const mainChannel = msg.mentions.channels.first();
const filePath = path.resolve(__dirname, './main-channel.json');
if (!mainChannel) {
console.log(`${cstTimeStamp} ${msg.author.tag} requested to set a main channel but didn't provide a channel\n`);
return msg.channel.send("There's no channel to set the main to");
}
try {
const currentSettings = await jsonRead(filePath);
currentSettings.channel = mainChannel;
jsonWrite(filePath, currentSettings);
console.log(`${cstTimeStamp} ${msg.author.tag} set the main channel as ${currentSettings.channel}\n`);
msg.channel.send(`Set the main channel as ${currentSettings.channel}`);
} catch (err) {
console.log(err);
}
}
});
client.once('ready', () => {
console.log('Bot is online\n');
});
client.login('Token hidden for safety reasons');
function jsonRead(filePath) {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf-8', (err, content) => {
if (err) {
reject(err);
} else {
try {
const parsedContent = JSON.parse(content);
resolve(parsedContent);
} catch (err) {
reject(err);
}
}
});
});
}
function jsonWrite(filePath, data) {
return new Promise((resolve, reject) => {
fs.writeFile(filePath, JSON.stringify(data), (err) => {
if (err) {
reject(err);
}
resolve(true);
});
});
}
Alright, I see what's going on here. I made the logic react to ONLY !setmainchannel, whereas I should've done if(msg.content.startsWith("!setmainchannel")!

Requests to Express app come with empty body though data being sent, but only in one route

it's nice to join the group of people brave enough to ask the questions on Stack, so that everyone cantake advantage :)
My problem is pretty strange. I'm writing an app in Express, I have two routes so far and everything is going pretty smoothly, yet I've encountered one problem, which I can not seem to solve. In one route, with the patch method, the incoming requests have emmpty body. The rest of app is running smoothly, everything is working fine and this one route seems to be broken, I can not figure out why. Strange enough, yet I found out that the requests DO have body in one case - when I'm sending requests with my tests (supertest) using the .send({ ... }) method. When I'm sending requests with .attach or .field - they come empty. Same with requests sent from Postman (empty). What is causing such strange behavior?
Here are my tests:
const request = require('supertest');
const Image = require('../models/image');
const app = require('../app');
const crypto = require('crypto');
const fs = require('fs')
const { setupImages } = require('./fixtures/db')
beforeEach(setupImages);
describe('[IMAGE] - ', () => {
test('Should get images', async () => {
const main_img = await Image.findOne({ main: true });
const image = await request(app)
.get(`/image/${main_img._id}`)
.expect(200);
expect(image.header['content-type']).toBe('image/png');
});
test('Should delete images', async () => {
const image = await Image.findOne({ description: 'Lorem ipsum' });
await request(app)
.delete(`/image/${image._id}`);
const imageFound = await Image.findById(image._id);
expect(imageFound).toBeNull();
});
//TEST THAT FAILS
test('Should edit images', async () => {
const image = await Image.findOne({ main: false });
await request(app)
.patch(`/image/${image._id}`)
.field('description', 'new desc')
.attach('image', './src/tests/fixtures/imgtest.png')
.expect(200);
const returnChecksum = file => {
return crypto
.createHash('md5')
.update(file, 'utf8')
.digest('hex')
}
const imageEdited = await Image.findById(image._id);
const newImageChecksum = returnChecksum(fs.readFileSync(__dirname + '/fixtures/imgtest.png'));
expect(returnChecksum(imageEdited.image)).toBe(newImageChecksum);
expect(imageEdited.description).toBe('new desc');
});
})
Here are image routes
const express = require('express');
const router = new express.Router();
const Image = require('../models/image');
const chalk = require('chalk');
router.get('/image/:id', async (req, res) => {
const { id } = req.params;
try {
const image = await Image.findById(id);
if (!image) {
return res.status(404).send()
}
res.set('Content-Type', 'image/png');
res.send(image.image);
} catch (e) {
console.log(chalk.red('Error serving image: ') + e);
res.send(500);
}
});
//THE ROUTE THAT FAILS
router.patch('/image/:id', async (req, res) => {
const { id } = req.params;
const updateFields = Object.entries(req.body);
console.log('image patch req body', req.body)
try {
const imageEdited = await Image.findById(id, function (err, doc) {
if (err) { return err; }
updateFields.forEach(field => doc[field[0]] = field[1])
doc.save(res.status(200).send(doc));
});
if (!imageEdited) {
res.status(400).send();
}
} catch (e) {
res.status(500).send();
console.log(chalk.red('Error editing image: ') + e);
}
});
router.delete('/image/:id', async (req, res) => {
const { id } = req.params;
try {
await Image.findByIdAndDelete(id);
res.status(200).send();
} catch (e) {
res.status(500).send();
console.log(chalk.red('Error deleting image: ') + e);
}
});
module.exports = router;
And my app.js file:
const express = require('express');
require('./db/mongoose');
const productRouter = require('./routers/product');
const imageRouter = require('./routers/image');
const app = express();
app.use(express.json());
app.use(productRouter);
app.use(imageRouter);
module.exports = app;
The result of console.log in image route:
console.log src/routers/image.js:30
image patch req body {}
And this is the behavior of the app with changed sending method in test:
test('Should edit images', async () => {
const image = await Image.findOne({ main: false });
await request(app)
.patch(`/image/${image._id}`)
// .field('description', 'new desc')
// .attach('image', './src/tests/fixtures/imgtest.png')
.send({description: 'new desc'})
.expect(200);
const returnChecksum = file => {
return crypto
.createHash('md5')
.update(file, 'utf8')
.digest('hex')
}
const imageEdited = await Image.findById(image._id);
const newImageChecksum = returnChecksum(fs.readFileSync(__dirname + '/fixtures/imgtest.png'));
expect(returnChecksum(imageEdited.image)).toBe(newImageChecksum);
expect(imageEdited.description).toBe('new desc');
});
console.log src/routers/image.js:30
image patch req body { description: 'new desc' }
Thanks in advance!
I've managed to fix it myself, the problem lied in fact that I've forgot about multer. So this strange behavior can be result of not using said library, even if you're not sending any files apparently.

Return value to variable from function

I am looking to return a value to a varible when I call the function in nodejs.
The output I am looking for is "Calling From Glasgow to Euston"
The output I am getting is "Calling From undefined to undefined"
Code is the following.
function trainstation(stx, callBack) {
MongoClient.connect(ttdb, function(err, db) {
if (err) throw err;
var dbo = db.db("ttdb");
var collection = dbo.collection("tlc");
var find = collection.find( { "Stanox" : stx } );
find.toArray(function(err, result) {
if (err) throw err;
db.close();
return callBack(result);
});
});
};
function gettrain(){
var ts1 = trainstation(9531, function(x){
return x[0]['Station Name'];
});
var ts2 = trainstation(31033, function(x){
return x[0]['Station Name'];
});
console.log("Calling From", ts1, "to", ts2);
};
gettrain();
Thanks :)
I don't use the MongoDB package and I don't have MongoDB up & running right now to test this, so I've written this code purely based on a quick read of the reference documentation. Perhaps you can test this and we'll fix any minor issues. Copy this code to a new source file and test it.
What I've done is to take advantage of the MongoDB package's promise features. You can see that the code is more linear and simpler to follow.
const MongoClient = require('mongodb').MongoClient;
const ttdb = 'mongodb://localhost:27017'; // or your DB URL
const trainstation = async (Stanox) => {
const client = MongoClient(ttdb);
await client.connect();
const dbo = client.db("ttdb");
const collection = dbo.collection("tlc");
const result = await collection.find({Stanox}).toArray();
client.close();
return result;
};
const gettrain = async () => {
const ts1 = await trainstation(9531);
const ts2 = await trainstation(31033);
const sn1 = ts1[0]['Station Name'];
const sn2 = ts2[0]['Station Name'];
console.log("Calling From", sn1, "to", sn2);
};
gettrain();

Transaction numbers are only allowed on storage engines that support document-level locking - MongodbMemoryServer/Mochai/Chai/Supertest

FIXED: USER storageEngine: "wiredTiger"
I use Mocha / Chai / Supertest and Mongodb-Memory-Server to test my app. But's I received error: Transaction numbers are only allowed on storage engines that support document-level locking
In real database and test by postman, it's working well.
My code:
In database.js
const mongoose = require('mongoose')
const { MongoMemoryReplSet } = require('mongodb-memory-server')
mongoose.set('useFindAndModify', false);
const connect = async () => {
try {
let url = process.env.MONGO_URL
let options = {
//Something
}
if (process.env.NODE_ENV === 'test') {
const replSet = new MongoMemoryReplSet();
await replSet.waitUntilRunning();
const uri = await replSet.getUri();
await mongoose.connect(uri, options)
//log connected
} else {
await mongoose.connect(url, options)
//log connected
}
} catch (error) {
//error
}
}
I have two model: Company and User. I made a function to add a member to company with used transaction. My code
const addMember = async (req, res, next) => {
const { companyId } = req.params
const { userId } = req.body
const session = await mongoose.startSession()
try {
await session.withTransaction(async () => {
const [company, user] = await Promise.all([
Company.findOneAndUpdate(
//Something
).session(session),
User.findByIdAndUpdate(
//Something
).session(session)
])
//Something if... else
return res.json({
message: `Add member successfully!`,
})
})
} catch (error) {
//error
}
}
Here's router:
router.post('/:companyId/add-member',
authentication.required,
company.addMember
)
Test file:
const expect = require('chai').expect
const request = require('supertest')
const app = require('../app')
describe('POST /company/:companyId/add-member', () => {
it('OK, add member', done => {
request(app).post(`/company/${companyIdEdited}/add-member`)
.set({ "x-access-token": signedUserTokenKey })
.send({userId: memberId})
.then(res => {
console.log(res.body)
expect(res.statusCode).to.equals(200)
done()
})
.catch((error) => done(error))
})
})
And i received error: Transaction numbers are only allowed on storage engines that support document-level locking'
How can I fix this?
Add retryWrites=false to your database uri. Example below:
mongodb://xx:xx#xyz.com:PORT,zz.com:33427/database-name?replicaSet=rs-xx&ssl=true&retryWrites=false

Categories

Resources