I'm following a tutorial and I'm at the point where I'm trying to send a data to my MySQL database using the app.post. When I go to the localhost site running the request (my localhost is localhost:8800/shoes) it doesn't update/insert the data, it only shows the current database I have in MySQL. But in the video as the JS file was saved, the data got uploaded immediately.
import express from "express"
import mysql from "mysql"
const app = express()
const db = mysql.createConnection({
host: "localhost",
user: "root",
password: "qwerty",
database: "marketplace"
})
app.get("/", (req, res) => {
res.json("this is the backend")
})
app.get("/shoes", (req, res) => {
const q = "SELECT * FROM `marketplace`.`shoes`"
db.query(q, (err, data) => {
if(err) return res.json(err)
return res.json(data)
})
})
app.post("/shoes", (req, res) => {
const q = "INSERT INTO `marketplace`.`shoes` (`id`, `prod_name`, `prod_description`, `image`) VALUES(?)";
const values = [
"222",
"item3",
"item 3 description",
"item3 image"
];
db.query(q, [values], (err, data) => {
if(err) return res.json(err)
return res.json(data)
})
})
app.listen(8800, () => {
console.log("connected to backend")
})
I tried to troubleshoot it by removing the app.get and I receive in my localhost is Cannot GET /shoes.
import express from "express"
import mysql from "mysql"
const app = express()
const db = mysql.createConnection({
host: "localhost",
user: "root",
password: "qwerty",
database: "marketplace"
})
app.get("/", (req, res) => {
res.json("this is the backend")
})
// app.get("/shoes", (req, res) => {
// const q = "SELECT * FROM `marketplace`.`shoes`"
// db.query(q, (err, data) => {
// if(err) return res.json(err)
// return res.json(data)
// })
// })
app.post("/shoes", (req, res) => {
const q = "INSERT INTO `marketplace`.`shoes` (`id`, `prod_name`, `prod_description`, `image`) VALUES(?)";
const values = [
"222",
"item3",
"item 3 description",
"item3 image"
];
db.query(q, [values], (err, data) => {
if(err) return res.json(err)
return res.json(data)
//return res.json("test")
})
})
app.listen(8800, () => {
console.log("connected to backend")
})
So I suspect the issue is in the app.post but I have the same exact code in the video. I even tried the async and it still doesn't work
app.post("/shoes", async (req, res)
Please help what to do
From this part of your description
I tried to troubleshoot it by removing the app.get and I receive in my localhost is Cannot GET /shoes.
It sounds like when you're trying to add data to the shoes table and thus invoke the app.post() method you're actually still calling the get method.
Look at the frontend code that is attempting to save the data and make sure you have something like method: post in the options. Or if you're using a tool like Postman to test the API, make sure postman is configured with the post method.
I'm attempting to use a variable userEmail (which is assigned the user's email who is currently logged into my app) as a query for my api as I only want to search and return documents from my mongodb that relate to that specific email. I'm struggling to figure out how to pass this variable from my reactjs app to my api and utilising it, I don't even know if it is possible so any help would be great.
I'm using axios to make my GET request.
api.js contains my api helper functions
export async function surveyApiGet () {
let response = await axios.get('http://localhost:6000/'); // dateApi.js
return response.data;
}
dateApi.js is the api surveyApiGet() calls and at the moment my query is just regex that matches any emails, rahter than filtering to just the current user.
let MongoClient = require('mongodb').MongoClient;
var url = "mongodb://127.0.0.1:27017/";
const express = require('express');
const app = express();
app.use(express.json());
app.get('/', function (req, res) {
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("manderleydb");
var query = { userId : /^(.)/ };
dbo.collection("manderleySurveyCompleted").find(query).sort({ date: 1}).limit(1)
.toArray(function(err, result) {
if (err) throw err;
console.log(result);
db.close();
res.status(200).json(JSON.stringify(result));
});
});
});
app.listen(6000, () => {
console.log('listening on port 6000');
});
Landing.js is where I make the call to my api helper function
surveyApiGet()
.then(response => {
// code
})
.catch(err => {
err.message;
});
For this, you can do a POST request to your Nodejs API and you can include the user's email with that request. To do so what you have to do is something like the following.
const usersEmail = "example#email.com"
Then through Axios, you can post this code to Nodejs API as follows.
const data = await axios.post("http://localhost:6000/", {
usersEmail : usersEmail
});
After you send this to Nodejs you can hold the value of the user's email through the request's body as follows. Change your endpoint to post instead of get.
app.post("/", function (req, res) {
const userEmail = req.body.userEmail;
//Put your MongoDB query and the status code here.
})
Drop a comment if you have any unclear points.
I have a problem to design communication with MySQL database in my Nodejs's app.
The biggest problem is that queries are async, so it becomes complicated to design my projects. For example, I have excercises.js
EXCERCISES.JS
var express = require('express');
var database = require('../database/database.js');
var router = express.Router();
console.log(database.db(saveDbData))
/* GET users listing. */
router.get('/', function(req, res, next) {
res.render('exercises',{title: 'Exercises', ex: #DATABASE RESULT});
});
module.exports = router;
In need to write query's result in ex field.
Then I write a module to handle mysql connection
DATABASE.JS
var pool = mysql.createPool({
connectionLimit: 10000,
host: 'localhost',
user: 'root',
password: 'password',
database: 'Example'
});
var results;
var db = function(){
pool.query('SELECT name FROM Exercises', function(error, results, fields){
if (error) throw error;
res = results;
})
return res;
}
module.exports = {
db: db,
}
Obviously, It doesn't work because pool.query is async.
The only alternative that I've found on the web is something like this:
EXERCISES.JS
var pool = mysql.createPool({
connectionLimit: 10000,
host: 'localhost',
user: 'root',
password: 'password',
database: 'Example'
});
pool.query('SELECT name FROM Exercises', function(error, results, fields){
if (error) throw error;
router.get('/', function(req, res, next) {
res.render('exercises',{title: 'Exercises', ex: result[0].name});
});
})
But in this way, mysql parts and routing/render parts are mixed. Is it still a well-designed solution? Are there more elegant solutions?
EDIT:
I have modified the files and I have used Promise like this
EXERCISES.JS
var express = require('express');
var database = require('../database/database.js');
var router = express.Router();
var data = database.db()
.then(
function(data){
console.log("Resolved");
/* GET users listing. */
router.get('/', function(req, res, next) {
res.render('exercises',{title: 'Exercises', ex: data[0].name});
});
})
.catch(
error => console.error(error));
module.exports = router;
DATABASE.JS
ar mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit: 10000,
host: 'localhost',
user: 'root',
password: 'password',
database: 'Example'
});
var res;
var db = function(){
return new Promise(function(resolve, reject){
pool.query('SELECT name FROM Exercises', function(error, results, fields){
if (error) reject(error);
resolve(results)
})
})
}
module.exports = {
db: db,
}
And it works, but I don't think it is the best solution. For example, what if I want to get data for render from more queries?
I'm new in these technologies so I'm not able to figure out the best way to integrate database and html pages's rendering.
Have you ever wondered why all web frameworks in node requires you to return responses using the res object instead of just return? It's because all web frameworks expect that you need to do something asynchronous.
Consider a web framework design similar to Laravel (PHP) or Spring Framework (Java):
// Theoretical synchronous framework API:
app.get('/path', function (request) {
return "<html><body> Hello World </body></html>";
});
Then if you need to do anything async you will face the issue that the data you're fetching hasn't returned by the time you need to return the HTTP request:
// Theoretical synchronous framework API:
app.get('/path', function (request) {
return ??? // OH NO! I need to return now!!
});
It is for this reason that web frameworks in javascript don't act on return values. Instead it passes you a callback to call when you are done:
// Express.js
app.get('/path', function (request, response) {
doSomethingAsync((err, result) => {
response.send(result);
});
});
So for your code you just need to do:
router.get('/', function(req, res) {
pool.query('SELECT name FROM Exercises', function(error, results, fields){
if (error) throw error;
res.render('exercises',{title: 'Exercises', ex: result[0].name});
});
});
Exporting the database
Exporting the database is as simple as exporting pool:
db.js
var pool = mysql.createPool({
connectionLimit: 10000,
host: 'localhost',
user: 'root',
password: 'password',
database: 'Example'
});
module.exports = {
pool: pool
}
exercises.js
let db = require('./db');
// you can now use db.pool in the rest of your code
// ..
Reusing your queries
Instead of coding SELECT statements in your controllers (routes) you can (and should) code them in your db module(s):
db.js
var pool = mysql.createPool({
connectionLimit: 10000,
host: 'localhost',
user: 'root',
password: 'password',
database: 'Example'
});
function getExerciseNames (callback) {
pool.query('SELECT name FROM Exercises',callback);
}
module.exports = {
pool: pool
}
Then in your controller logic you just need to do:
router.get('/', function(req, res) {
db.getExerciseNames(function(error, results, fields){
if (error) throw error;
res.render('exercises',{
title: 'Exercises',
ex: result[0].name
});
});
});
Caching
If your intention is to query the db only once to cache the value of Exercises then don't invert the Express routing flow. Instead implement the caching at your db layer:
db.js:
var exerciseNamesCache = [];
var exerciseNamesFields = [];
function getExerciseNames (callback) {
if (exerciseNamesCache.length > 0 && exerciseNamesFields.length > 0) {
callback(null, exerciseNamesCache, exerciseNamesFields);
}
pool.query('SELECT name FROM Exercises',function(error, results, fields){
if (!error) {
exerciseNamesCache = results;
exerciseNamesFields = fields;
}
callback(error, results, fields);
});
}
Promises
Promises is a design pattern for handling callbacks. It is comparable to Java's Futures (CompletionStage etc.) only a lot more lightweight. If an API you are using returns a promise instead of accepting a callback then you need to call res.render() inside the promise's .then() method:
router.get('/', function(req, res, next) {
doSomethingAsync()
.then(function(result){
res.send(result);
})
.catch(next); // remember to pass on asynchronous errors to next()
});
If the API you're using accepts a callback then weather or not you wrap it in a promise is more a matter of taste. I personally wouldn't do it unless you are also using another API that returns a promise.
async/await
One advantage of promises is that you can use them with await. Express specifically works well with async/await. Just remember you can only use await inside a function marked with async:
router.get('/', async function(req, res, next) {
let result = await doSomethingAsync();
res.send(result);
});
Multiple asynchronous operations
Fetching multiple asynchronous data can be as simple as:
router.get('/', function(req, res, next) {
doSomethingAsync(function(result1){
doSomethingElse(function(result2) {
res.json([result1, result2]);
});
});
});
With promises that would be:
router.get('/', function(req, res, next) {
doSomethingAsync()
.then(function(result1){
return doSomethingElse()
.then(function(result2) {
return [result1, result2];
});
})
.then(function(results){
res.json(results);
})
.catch(next);
});
But both the above code perform the requests sequentially (get result1 then get result2). If you want to fetch both data in parallel you can do this with Promises:
router.get('/', function(req, res, next) {
Promise.all([
doSomethingAsync(), // fetch in parallel
doSomethingElse()
])
.then(function(results){
res.json(results);
});
})
With callbacks it's a little bit more complicated. There is a design pattern you can use and someone has actually implemented it as a library called async.js but often the easiest solution is to wrap them in Promises and use Promise.all(). Still, do check out async.js since it has functionality useful for things like batching requests, perform async operations while a condition is true etc. (the promise based counterpart of that library is async-q)
You can use npm modules for achieving the async task with MySQL.
I recommended to choose sequilize or jm-ez-mysql. If you go with jm-ez-mysql then your code structure like
server.js
require('./config/database.js');
./config/database.js
const sql = require('jm-ez-mysql');
// Init DB Connection
const connection = My.init({
host: process.env.DBHOST,
user: process.env.DBUSER,
password: process.env.DBPASSWORD,
database: process.env.DATABASE,
dateStrings: true,
charset: 'utf8mb4',
timezone: 'utc',
multipleStatements: true,
});
module.exports = {
connection,
};
After that, you can use MySQL asynchronously.
./exercise.js
const sql = require('jm-ez-mysql');
const exerciseUtil = {};
exerciseUtil.searchUserById = async (id) => {
try {
// table name, db fields, condition, values
const result = await sql.first('users', ['id, name, email'], 'id = ?', [id]);
return result; // Which return your result in object {}
} catch (err) {
console.log(err);
throw err;
}
};
module.exports = exerciseUtil;
I hope it helps.
Happy Coding :)
I am trying to connect mysql with node.js but I got an undefined when I do console.log(result). This is my code:
dbConnection.js
const mysql = require('mysql');
module.exports = () => {
return mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'news_portal'
});
}
news.js
const dbConnection = require('../../config/dbConnection');
module.exports = app => {
const connection = dbConnection();
app.get('/', (req, res) => {
connection.query('SELECT * FROM news', (err, result) => {
console.log(result);
});
});
}
The database has info, and the user and password is correct. Can someone help me? Thanks.
I finally solve it. err var contained Client does not support authentication protocol requested by server; consider upgrading MySQL client. And I found a solution to that error in this post
Basically what I did was:
use mysql;
ALTER USER 'root'#'localhost' IDENTIFIED WITH mysql_native_password BY 'YOUR_MYSQL_PASSWORD'
Thanks for the help.
I have 3 files. db.js, app.js, commentController.js.
I am including my connection in every request in my app so that I wont be repeating the code connection again and again. Is this a bad / unsecure practice? Is there a better/proper way to implement this?
db.js
const mysql = require('mysql');
const pool = mysql.createPool({
host : 'host',
user : 'user',
password : 'password',
database : 'dbname'
});
exports.pool = pool;
app.js
const db = require('./db');
app.use((req, res, next) => {
req.pool = db.pool;
next();
});
commentController.js
exports.showComments = (req, res) => {
req.pool.getConnection((err, conn) => {
conn.query(`SELECT * FROM comments`, (err, results, fields) => {
conn.release();
if (err) throw err;
res.render('comments', { results });
});
});
};
If your only reason for doing this is to avoid duplicating code, then I think it's a bad idea. People looking at your code (or you looking at your code in a year) aren't going to naturally expect a db connection to be a property of req. And you aren't saving yourself any trouble really.
Just require() the database pool in the file and use it.
commentController.js
const db = require('./db');
require() will return the same pool to all your modules.
It's also not clear why you are requesting a connection rather than using the pool (I'm making some assumptions about the lib you're using).
Normally you should be able to do:
const db = require('./db');
exports.showComments = (req, res) => {
db.query(`SELECT * FROM comments`, (error, results, fields) => {
if (err) throw err;
res.render('comments', { results });
});
});
This saves the trouble of requesting and returning connections and just lets the pool do it's work.