Express-winston middleware error on GET and POST request to mongoDB - javascript

I have the following structure:
logger.js:
const logger = module.exports = require('winston')
logger.add(new logger.transports.File(
{
name: 'debug-file',
filename: 'log.log',
level: 'debug',
handleExceptions: true,
humanReadableUnhandledException: true,
exitOnError: true,
json: false,
maxsize: 104857600,
maxfiles: 5
}))
logger.add(new logger.transports.Console(
{
name: 'error-console',
level: 'error',
handleExceptions: true,
humanReadableUnhandledException: true,
exitOnError: true
}))
server.js:
const port = process.env.PORT || 5000;
const logger = require('./logger.js')
const database = require('./database/createDatabase.js')({ logger })
const app = require('./app/createExpressApp.js')
const server = require('http').createServer()
server
.on('request', app)
.on('listening', function() {
const addr = this.address()
const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`
logger.info(`Listening on ${bind}`)
})
.on('error', function(error) {
if (error.syscall !== 'listen') throw error
const addr = this.address() || { port }
const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`
switch (error.code) {
case 'EACCES':
logger.error(`${bind} requires elevated privileges`)
process.exit(1)
case 'EADDRINUSE':
logger.error(`${bind} is already in use`)
process.exit(1)
default:
throw error
}
})
.listen(port)
createDatabase.js:
const mongoose = require('mongoose')
const glob = require('glob')
const path = require('path')
module.exports = ({ logger }) => {
const url = process.env.ATLAS_URI
|| "mongodb+srv://(removed for stackoverflow question)"
mongoose.connect(url)
const db = glob.sync('./schemas/**/*.js', { cwd: __dirname })
.map(filename => {
return {
schema: require(filename),
name: path
.basename(filename)
.replace(path.extname(filename), ''),
}
})
.map(({name, schema}) => mongoose.model(name, schema))
.reduce((db, model) => {
return {
...db,
[model.modelName]: model,
}
}, {})
mongoose
.connection
.on('error', error => {
throw error
})
.once('open', () => logger.info(`MongoDB connection established successfully!`) &&
console.log(`MongoDB connection established successfully!`))
return db
}
and finally getUsers.js:
const Router = require('express').Router
// export to router
module.exports = Router({mergeParams: true})
.get('/v1/users', async (req, res, next) => {
try {
const users = await req.db.User.find()
res.send(users)
}
catch (error) {
next(error)
}
})
I have triple checked folder structure, syntax and everything else I can think of, but think I lack understanding of winston. I get the following error when I go to perform GET request for Users:
{"error":{},"level":"error","message":"uncaughtException: transports or a winstonInstance are required by express-winston middleware
I have a feeling its a rudimentary error and I'm missing something simple. Anyone have ideas on what would be causing the error?

This is because your logger, and database are not imported into your server.js
Change your server.js imports from
const port = process.env.PORT || 5000;
const logger = require('./logger.js')
const database = require('./database/createDatabase.js')({ logger })
const app = require('./app/createExpressApp.js')
const server = require('http').createServer()
to
const port = process.env.PORT || 5000;
const logger = require('./logger.js')
const database = require('./database/createDatabase.js')({ logger })
const app = require('./app/createExpressApp.js')({ logger, database });
const server = require('http').createServer()
both, database and the Winston logger are exported, however, they are not being pushed to the createExpressApp.js, which is needed and will remove this error and log the requests from postman/server properly in your log file.
This is an error from express-winston, which requires the winstonInstance to not be null. I bet if you try to console.log(logger) in your createExpressApp.js it will come back undefined.
Per the express-winston documentation: https://www.npmjs.com/package/express-winston
PS. Ensure you add:
mongoose.connect(url, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true,
});
these methods to your mongoDB URL, or your will get depreciation warnings :D

Related

Uncaught TypeError TypeError: Cannot read property 'cache' of undefined Discord.js

I have a problem with 'cache'. I had an error before with 'guilds' that I fixed but now it's the 'cache' that has a problem.
I have this error in the console when I click on the web page
Uncaught TypeError TypeError: Cannot read property 'cache' of undefined
at <anonymous> (c:\Users\elelo\OneDrive\Bureau\bot discord serv NFT\website\public\getUserGuilds.js:29:31)
at run (c:\Users\elelo\OneDrive\Bureau\bot discord serv NFT\website\public\getUserGuilds.js:27:20)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
Here is the link to the old question asked Old question guilds
Code file getUserGuilds.js
const { Permissions } = require('discord.js');
const client = require('../../index');
const schema = require('../../model/dashboard');
const jwt = require('jsonwebtoken');
const { jwt_secret } = require('../../config.json');
module.exports = {
name: "/getUserGuilds/",
run: async (req, res) => {
delete require.cache[require.resolve("../html/getUserGuilds.ejs")];
if (!req.cookies.token) return res.redirect('/login')
let decoded;
try {
decoded = jwt.verify(req.cookies.token, jwt_secret);
} catch (e) { }
if (!decoded) res.redirect('/login');
let data = await schema.findOne({
_id: decoded.uuid,
userID: decoded.userID
});
if (!data) res.redirect('/login');
let guildArray = await process.oauth.getUserGuilds(data.access_token);
let mutualArray = [];
guildArray.forEach(g => {
g.avatar = `https://cdn.discordapp.com/avatars/${g.id}/${g.icon}.png`;
if (client.guilds.cache.get(g.id)) {
const bitPermissions = new Permissions(g.permissions_new);
if (bitPermissions.has(Permissions.FLAGS.MANAGE_GUILD) || bitPermissions.has(Permissions.FLAGS.ADMINISTRATOR) || client.guilds.cache.get(g.id).ownerID == data.userID) g.hasPerm = true
mutualArray.push(g);
} else g.hasPerm = false;
});
let args = {
avatar: `https://cdn.discordapp.com/avatars/${data.userID}/${data.user.avatar}.png`,
username: data.user.username,
discriminator: data.user.discriminator,
id: data.user.userID,
loggedIN: true,
guilds: guildArray,
adminGuilds: mutualArray
};
res.render('./website/html/getUserGuilds.ejs', args);
}
}
Code file index.js
const Discord = require('discord.js');
const { Intents } = Discord;
const axios = require('axios');
const express = require("express");
const app = express()
const fs = require("fs");
const DiscordOauth2 = require('discord-oauth2');
const cookieParser = require('cookie-parser');
const mongoose = require('mongoose');
const { token, clientId, clientSecret } = require('./config.json');
const client = new Discord.Client({
intents:
[
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MEMBERS
]
});
require('dotenv').config();
const prefix = "k!";
mongoose.connect(process.env.DATABASE_URI, {
autoIndex: false,
maxPoolSize: 10,
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
family: 4
}).then(() => { console.log('[Database] - La base de donnée est connectée') })
.catch(err => {console.log(err)})
app.enable("Trust proxy") // if this ip is ::1 it means localhost
app.set("etag", false) // disable cache
app.use(express.static(__dirname + "/website"))
app.set("views", __dirname)
app.set("view engine", "ejs")
app.use(cookieParser());
process.oauth = new DiscordOauth2({
clientId: clientId,
clientSecret: clientSecret,
redirectUrl: "http://localhost:90/callback"
})
client.on("ready", () => {
console.log("[BOT] - Le Bot est opérationnel");
getGas();
});
How do I fix this?
with things like this i find using client.guilds.fetch() to work better and more smoothly.
// async the forEach function param
guildArray.forEach(async g => {
g.avatar = `https://cdn.discordapp.com/avatars/${g.id}/${g.icon}.png`;
// awaits the fetching a the guild, for discord's sake
await client.guilds.fetch(g.id)
.catch(err => err) // caution of error
.then(guild => {
// bool based on if client was able to fetch guild
if (guild !== undefined) {
// if yes
const bitPermissions = new Permissions(g.permissions_new)
if (bitPermissions.has(Permissions.FLAGS.MANAGE_GUILD) ||
bitPermissions.has(Permissions.FLAGS.ADMINISTRATOR) ||
client.guilds.cache.get(g.id).ownerID == data.userID) g.hasPerm = true
mutualArray.push(g)
} else g.hasPerm = false; // if no
})
});
Why fetch and not get?
The Fetch function allows you to asynchronously request for a resource. If the request fails due to some network problems, the promise is rejected. async/await syntax fits great with fetch() because it simplifies the work with promises. Meaning, we wait on discord's time. But with a lesser chance of error.

Cannot POST /api/sentiment

I'm testing the endpoint for /api/sentiment in postman and I'm not sure why I am getting the cannot POST error. I believe I'm passing the correct routes and the server is listening on port 8080. All the other endpoints run with no issue so I'm unsure what is causing the error here.
server.js file
const express = require("express");
const cors = require("cors");
const dbConfig = require("./app/config/db.config");
const app = express();
var corsOptions = {
origin: "http://localhost:8081"
};
app.use(cors(corsOptions));
// parse requests of content-type - application/json
app.use(express.json());
// parse requests of content-type - application/x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }));
const db = require("./app/models");
const Role = db.role;
db.mongoose
.connect(`mongodb+srv://tami00:MEUxClWqUNbLz359#cluster0.gmvao.mongodb.net/test?retryWrites=true&w=majority`, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log("Successfully connect to MongoDB.");
initial();
})
.catch(err => {
console.error("Connection error", err);
process.exit();
});
// simple route
app.use('/api/favourite', require('./app/routes/favourite.routes'));
app.use('/api/review', require('./app/routes/review.routes'));
app.use('/api/sentiment', require('./app/routes/sentiment-analysis.routes'));
// routes
// require(".app/routes/favourite.routes")(app);
require("./app/routes/auth.routes")(app);
require("./app/routes/user.routes")(app);
// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
function initial() {
Role.estimatedDocumentCount((err, count) => {
if (!err && count === 0) {
new Role({
name: "user"
}).save(err => {
if (err) {
console.log("error", err);
}
console.log("added 'user' to roles collection");
});
new Role({
name: "creator"
}).save(err => {
if (err) {
console.log("error", err);
}
console.log("added 'creator' to roles collection");
});
new Role({
name: "watcher"
}).save(err => {
if (err) {
console.log("error", err);
}
console.log("added 'watcher' to roles collection");
});
}
});
}
sentiment-analysis routes file
const express = require('express');
const router = express.Router();
const getSentiment = require('../sentiment-analysis/sentimentAnalysis')
router.post('/api/sentiment', (req, res) => {
const data = req.body.data
const sentiment = getSentiment(data)
return res.send({sentiment})
})
module.exports = router;
sentimentAnalysis.js file
const aposToLexForm = require("apos-to-lex-form");
const {WordTokenizer, SentimentAnalyzer, PorterStemmer} = require("natural");
const SpellCorrector = require("spelling-corrector");
const stopword = require("stopword");
const tokenizer = new WordTokenizer();
const spellCorrector = new SpellCorrector();
spellCorrector.loadDictionary();
const analyzer = new SentimentAnalyzer('English', PorterStemmer, 'afinn')
function getSentiment(text){
if(!text.trim()) {
return 0;
}
const lexed = aposToLexForm(text).toLowerCase().replace(/[^a-zA-Z\s]+/g, "");
const tokenized = tokenizer.tokenize(lexed)
const correctSpelling = tokenized.map((word) => spellCorrector.correct(word))
const stopWordsRemoved = stopword.removeStopwords(correctSpelling)
console.log(stopWordsRemoved)
const analyzed = analyzer.getSentiment(stopWordsRemoved);
console.log(analyzed)
}
module.exports = getSentiment;
console.log(getSentiment("Wow this is fantaztic!"))
console.log(getSentiment("let's go together?"))
console.log(getSentiment("this is so bad, I hate it, it sucks!"))
I see that you use your routes like: app.use('/api/sentiment', require('./app/routes/sentiment-analysis.routes'));. But then in your sentiment-analysis you again use /api/sentiment so your request URL should be /api/sentiment/api/sentiment
Shouldn't it be:
const data = req.body.data

How come fetch only works here when I add an alert to the end of the line? Express + NodeJS + Fetch. What's a good fix here

I'm using NodeJS w/ Express to create a web app that records your audio using the VMSG library and posts the BLOB audio to my file system using HTTP Requests and multer. It also adds that instance of a recording into a MongoDB database.
I'm having an issue with the fetch command. It's not working unless I put an alert right after the fetch. The way I have it set up is that I have my main express app (index.js), and a router to the /recordingsDirectory (recordings.js) which is the endpoint for processing the posts. My main index HTML page uses Handlebars and uses a separate JS script (recorder.js) to 1) use the VMSG library and 2) fetch a POST to the /recordingsDirectory once someone submits the audio file w/ the name and the AudioBlob present. This is where I'm stuck. I can fetch in recorder.js with an alert line after the fetch, but I can't have the fetch on the end of the else if block by itself. I'd like to do it without this since the alert is ugly. A solution I've tried is that I tried to make the onsubmit function async and await fetch since I thought maybe it's waiting for a promise but that didn't work.
Here are the files. I commented CRITICAL and SUPER CRITICAL to the lines of code that you should check out and I think where the issues lie:
index.js
const express = require('express')
const handlebars = require('express-handlebars')
const path = require('path')
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
const xhr = new XMLHttpRequest()
const db = require('./db')
const app = express()
const PORT = process.env.PORT || 8000
app.set('view engine', 'hbs')
app.engine('hbs', handlebars({
layoutsDir: path.join(__dirname, 'views', 'layouts'),
extname: 'hbs',
defaultLayout: 'index',
partialsDir: path.join(__dirname, 'views', 'partials'),
}))
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.use((err, req, res, next) => {
if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
return res.status(400).send({ status: 404, message: err.message })
}
next()
})
app.get('/', (req, res) => {
res.render('main', {
title: 'Main Page'
})
})
app.get('/recordings', (req, res) => {
var database = db.get().db('AudioJungle')
database.collection('recordings').find().sort({ "date": -1 }).toArray(function(err, docs) {
res.render('recordings', {
title: 'Recordings',
recordings: docs
})
})
})
// CRITICAL
app.use('/recordingsDirectory', require('./recordings/recordings'))
app.use(express.static('public'))
app.use('/scripts', express.static(path.join(__dirname, 'node_modules', 'vmsg')))
db.connect(function(err) {
if (err) {
console.log('Unable to connect to Mongo.')
process.exit(1)
} else {
app.listen(PORT, () => console.log(`Listening on Port: ${PORT}`))
}
})
process.on('SIGINT', function() {
db.close(function () {
console.log('Disconnected on app termination');
process.exit(0);
});
});
app.use((req, res, next) => {
res.status(404).send({
status: 404,
error: 'Not found'
})
})
recordings.js (Aka the /recordingsDirectory endpoint for a fetch POST)
const express = require('express')
const router = express.Router()
const multer = require('multer')
const fs = require('fs-extra')
const db = require('../db')
const { ObjectId } = require('bson')
const moment = require('moment')
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, callback) => {
let path = './public/uploads'
fs.mkdirsSync(path)
callback(null, path)
},
filename: (req, file, callback) => {
createRecording(req).then((id) => {
var file_name = id + '.mp3'
callback(null, file_name)
})
}
})
})
var type = upload.single('audio-file')
// CRITICAL
router.post('/', type, (req, res) => {
console.log('made it')
res.status(200)
res.send('OK')
})
router.delete('/delete', (req, res) => {
deleteRecording(req.body._id).then((dbResponse) => {
if (dbResponse == null || dbResponse == undefined) {
res.status(400).json({ msg: 'ID already deleted' })
} else {
res.status(200)
}
})
})
router.get('/', (req, res) => {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
recordings.findOne({"_id": ObjectId(req.query.id)}, function(err, result) {
if (err) throw err
if (result == null || result == undefined) {
return res.status(400).json({
status: 404,
error: 'Recording no longer in the database'
})
}
res.status(200)
res.json({
name: result.name,
date: result.date
})
})
})
async function createRecording(req) {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
var audioObject = {
name: req.body.name,
date: moment().format('MMMM Do YYYY, h:mm:ss a')
}
var dbResponse = await recordings.insertOne(audioObject)
return dbResponse.insertedId
}
async function deleteRecording(id) {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
var audioToDelete = {
_id: ObjectId(id)
}
var deleteResult = await recordings.deleteOne(audioToDelete)
return deleteResult
}
module.exports = router
And below is the Script the audio and name and tries to Fetch (where I need the alert for it to actually process into the /recordingsdirectory)
recorder.js
import { record } from "/scripts/vmsg.js";
let recordButton = document.getElementById("record");
var blobObj = null
recordButton.onclick = function() {
record({wasmURL: "/scripts/vmsg.wasm"}).then(blob => {
blobObj = blob
var tag = document.createElement("p")
tag.id="finishedRecording"
var text = document.createTextNode("Audio File Recorded")
tag.appendChild(text)
var element = document.getElementById("box")
element.appendChild(tag)
document.getElementById('box').appendChild(a)
})
}
let form = document.getElementById('mp3Form');
form.addEventListener("submit", submitAudio)
function submitAudio() {
var fileName = form.elements[0].value
if (fileName == "") {
alert('Please enter a name for your file')
} else if (blobObj != null) {
// CRITICAL
// SUPER CRITICAL WHERE FETCH DOESN'T WORK UNLESS I PUT AN ALERT AT THE END
const formData = new FormData()
formData.append('name', fileName)
formData.append('audio-file', blobObj)
const options = {
method: 'POST',
body: formData
}
fetch('/recordingsDirectory', options);
// If I comment an alert here, /recordingsDirectory will process the post since it console.logs 'made it'
} else {
alert('Record some Audio to upload')
}
}
Here's my file system.
Also, I'd like to mention that the fetch works properly on my Windows PC without having to add the alert, but it doesn't work without the alert on my macbook. If any one figures out a fix or an error in how I'm doing things to allow this please let me know. I've been stuck on this problem for a day now. Thanks a bunch!

POST request body is undefined using koa-body

Its my first time trying to do a POST request with Postman using Koa in my application. I have the router and the body parser but for some reason i still get an error message sayng that my request body is undefined. I think the body parser is not working but i have no idea why.
routes.js
const Koa = require('koa');
const bodyParser = require('koa-body')
const Router = require('koa-router')
const app = new Koa()
const router = new Router()
const Topic = require('./models/topic')
router.post('/topics', bodyParser(), async (ctx) => {
console.log(JSON.stringify(ctx.request.body))
const { name } = ctx.request.body
newPost = {
name: {name}
}
let newTopic = new Topic(newPost)
await newTopic.save(function(error, newPost){
if (error) {
console.log(error)
} else {
res.status(201).json({
message : 'Name added!'
}).send(newPost)
}
})
return
})
app
.use(router.allowedMethods())
.use(router.routes())
module.exports = router
topic.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const TopicSchema = new Schema(
{
name: {type: String, required: true },
viewCount: {type: Number, default: 0 }
},
{
timestamps: true
}
)
module.exports = mongoose.model('two/Topic', TopicSchema)
Error message:
{}
Error: two/Topic validation failed: name: Cast to string failed for value "{ name: undefined }" at path "name"
at ValidationError.inspect (/home/node/app/node_modules/mongoose/lib/error/validation.js:47:26) ...
EDIT
Also adding in server.js for further reference
const Koa = require('koa');
const mongoose = require('mongoose');
const router = require('./routes');
const app = new Koa();
app.use(require('koa-body')());
app.use(router.routes());
mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
const listener = app.listen(process.env.APP_PORT || 3000, () =>
console.log('App started on port ' + listener.address().port)
)
})
.catch((error) => {
console.log(error)
process.exit(1)
})
// app.proxy = true;
module.exports = app;

Why is my callback not working correctly?

This method runs at node server
const express = require("express");
const app = express();
const fs = require("fs");
const connectDb = require("./config/db");
const __init__ = (local = false) => {
fs.writeFile(
"./config/default.json",
`{
"mongoURI": ${
local
? `"mongodb://127.0.0.1:27017/test"`
: `"mongodb+srv://admin:<password>#abc-xxghh.mongodb.net/test?retryWrites=true&w=majority"`
}
}`,
function(err) {
if (err) {
return console.log(err);
}
connectDb();
}
);
};
__init__(true);
The problem is that if originally mongoURI: 127.0.0.1:27017, and if I do __init__(false), Node will try to connect to 127.0.0.1:27017, when it should be connecting to +srv uri.
If I run __init__(false) AGAIN, then it will connect to appropriate link.
Likewise, if I then run __init__(true), it will connect to srv+ when it should be connecting to local, and if I run __init__(true) again, only then it will connect to local.
What am I doing wrong here? I'm using the callback as Im supposed to, no?
Edit:
//config/db
// for mongoDB connection
const mongoose = require("mongoose");
// require the directory
const config = require("config");
// get all contents of JSON file
const db = config.get("mongoURI");
const connectDb = async () => {
try {
console.log("connecting to mongodb", db);
await mongoose.connect(db, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true
});
console.log("Mongo DB connected");
} catch (err) {
console.log("unable to connect to mongodb");
console.log(err.message);
//exit if failure
process.exit(1);
}
};
module.exports = connectDb;
I've even tried doing the following:
.....
console.log("Developing locally:", local);
// require the directory
const config = require("config");
// get all contents of JSON file
const db = config.get("mongoURI");
connectDb(db);
.....
But it still reads the old value
The problem is on execution order since the require is sync
The order now is:
const connectDb = require("./config/db");
const config = require("config");
const db = config.get("mongoURI"); // this has the OLD VALUE
fs.writeFile(...
await mongoose.connect(db, { // this is using the OLD REFERENCE
So you need to change your connectDb function like this:
const connectDb = async () => {
const config = require("config");
// get all contents of JSON file
const db = config.get("mongoURI");
try {
console.log("connecting to mongodb", db);
await mongoose.connect(db, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true
});
console.log("Mongo DB connected");
} catch (err) {
console.log("unable to connect to mongodb");
console.log(err.message);
//exit if failure
process.exit(1);
}
};
Anyway, I think this is not a nicer way to load config based on the environment, so I would suggest improving it using factory pattern.
Your code for URL local vs srv+ is correct. Problem i could see is placement of method connectDb();
fs.writeFile("fir arg - URL", "second -content", third - error fun {});
where in your code after function, connectDb() is placed after error fun. After it should be closed.

Categories