I'm working on a project that uses ReactJS typescript for the front-end, express for the back-end, and MongoDB for the database.
The main issue I am having is that I want to somehow send data from my React component to the express app so that it can query and add things to the database.
Currently, I have the express server running on http://localhost:9000, and the React app on http://localhost:3000, and I can connect them using routes.
My express app looks like the following:
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require('cors');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var testAPIRouter = require('./routes/testAPI');
var testAddUser = require('./routes/addUser');
const MongoClient = require('mongodb').MongoClient;
const mongoose = require('mongoose');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use("/testAPI", testAPIRouter);
app.use("/addUser", testAddUser);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
const dbRoute = 'mongodb+srv://Adminname:fjfeinjd#pawornaw-b4vzg.gcp.mongodb.net/test?retryWrites=true&w=majority';
mongoose.connect(dbRoute,
{useNewUrlParser: true})
.then(() => console.log("Connected to MongoDB"))
.catch(err => console.error("Could not connected to Mongo"));
module.exports = app;
and my React Component is this, minus import statements. The render function only contains a button that has an onlclick that executes doThing()
constructor(props: any) {
super(props);
this.state = {
showHomePage: true,
showAnimalUploadSearch: false,
showProfile: false,
showAnimal: true,
apiResponse: "",
fName: "bob"
};
this.changeView = this.changeView.bind(this);
// this.callAPI = this.callAPI.bind(this);
// this.componentWillMount = this.componentWillMount.bind(this);
this.doThing = this.doThing.bind(this);
}
callAPI() {
fetch("http://localhost:9000/testAPI")
.then(res => res.text())
.then(res => this.setState({apiResponse: res}))
.catch(err => err);
}
componentWillMount(): void {
this.callAPI();
}
changeView() {
this.setState({showHomePage: !this.state.showHomePage});
this.setState({showAnimalUploadSearch: !this.state.showAnimalUploadSearch});
this.setState({showAnimal: true});
this.setState({showProfile: false});
}
doThing() {
Axios.post('http://localhost:9000/testAPI', ({firstName: this.state.fName}))
.then(res => console.log(res));
}
and finally, testAPI.js looks like this
const router = express.Router();
const axios = require('axios');
router.get('/', function(req, res, next) {
//res.send('API is working properly');
axios.get('http://localhost:3000')
.then(res => console.log("got it"))
.catch(err => err);
});
module.exports = router;
I want to be able to access and use the data that is sent from my react component so that I can query my database with user input in the future. The API does connect with my React code, and when the testAPI function only contains these lines:
const router = express.Router();
const axios = require('axios');
router.get('/', function(req, res, next) {
res.send('API is working properly');
});
module.exports = router;
the message can be displayed on my react app in the browser via the state.
If anyone could help me see what I am doing wrong, or maybe give me a clue as to what other options I can try, please let me know.
Thank you.
When you send post request from client side, it will be in body property of req object
const router = express.Router();
// you shoud listen post request
router.post('/', function(req, res) {
const { body } = req;
// do somethin with data which you recieved in body, save to database for example
// and send response to the client
res.json({ message: 'your data was saved'});
});
module.exports = router;
to send data to client use:
router.get('/', function(req, res) {
res.json({ data: 'Some data'}); // or res.send('some text') to send plain text
});
Related
I am making a Web-Notepad using Nodejs and express where all the data is gonna be saved in MongoDB. I want to grab the data through my Rest API making an HTTP request with Axion.
When I send the GET request, the program doesn't wait for the JSON file, continues and because of that, it exports an undefined file with the site is getting shown without the data.
With the console.log after the GET request, I get all the data I need - but too late.
app.js:
const express = require('express');
const chalk = require('chalk');
const debug = require('debug')('app');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv/config')
const app = express();
const port = 3000;
app.use(cors());
app.use(express.static('views'));
app.use(bodyParser.json());
app.set('views', './views');
app.set('view engine', 'ejs');
const postsRoute = require('./routes/posts');
// Here i import the data from the GET request
const getData = require('./routes/router');
app.use('/posts', postsRoute);
// The outcome of this log is; Promise {<pending>}
console.log(getData);
app.get('/', (req, res) => {
res.render(
'index',
{
// Here i want to send the Data to the ejs file
getData,
title: 'Notepad'
});
});
// Connect to DB
mongoose.connect(
process.env.DB_CONNECTION,
{useUnifiedTopology: true, useNewUrlParser: true, useCreateIndex: true, useFindAndModify: false}, () =>
debug('Connected correctly to MongoDB')
);
app.listen(port, () => {
debug(`Listening on port ${chalk.green(port)}`);
});
router.js where i make the GET request (i should change the name of the file...)
const axios = require('axios').default;
async function getData() {
try {
const response = await axios.get('http://localhost:3000/posts');
console.log(response);
return response.data
} catch (err) {
console.log(err);
}
}
module.exports = getData();
GET Request:
router.get('/', async (req, res) => {
try {
const posts = await post.find();
res.json(posts);
} catch (err) {
res.json({message: err})
}
});
my database in mongoDb is connected to my nodeJS i can read it there my nodeJs api is connected to my client-side (in reactJS) and i can send data from my nodeJs api using express-generator to my client-side and is working but when i tried to send my mongoDb database to the client-side is not working( but i'm still getting status 200 but my array is not here . I can't figure out why? i cant see the db when i call the api in postman so i assume the error is in the server-side . If i had a consol.log i can see the db but when i use return it is not working and i cant see the data in postman
here my nodeJs code:
var mongodb = require('mongodb')
var MongoClient = mongodb.MongoClient
var connectionURL = 'mongodb://127.0.0.1:27017'
var databaseName = 'projet_Ecommerce';
const dataFromDb = () => {
MongoClient.connect(connectionURL, {
useNewUrlParser: true
}, (error, client) => {
if (error) {
return console.log('Unable to connect to database')
}
console.log('Connected correctly !');
var db = client.db(databaseName)
db.collection('product').find().toArray(function(error, data) {
if (error) {
return console.log('Unable to find the user')
}
return (data);
})
// Pointer - go to doc
// db.collection('tasks').find({completed: false}).toArray()
})
};
module.exports = dataFromDb
routres / index.js:
var express = require('express');
var router = express.Router();
const bodyParser = require('body-parser')
var dataC = require('../public/javascripts/dataFromDb')
// data = JSON.stringify(data);
// console.log(dataFromDb())
/* GET home page. */
router.get('/', function(req, res, next) {
//console.log(dataFromDb())
res.send(dataC())
});
//console.log(dataFromDb())
module.exports = router;
app.js:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require("cors")
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var testAPIRouter = require("./routes/testAPI");
var app = express();
var bodyParser = require("body-parser")
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
// app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.urlencoded({
extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use("/testAPI", testAPIRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
other files no change
I'm trying to run a simple query from an express route:
var router = require('express-promise-router')()
const { Pool } = require('pg')
const pool = new Pool({
user: 'user',
password: 'password',
host: 'host',
port: 1234,
database: 'db'
})
router.get('/', async (req, res) => {
console.log('OK')
try {
const { rows } = await pool.query('Select VERSION()')
console.log(rows)
}
catch(e) {
console.log(e)
}
console.log('DONE')
})
module.exports = router
'OK' Prints after sending the request but rows, e, or 'DONE' never print. I'm following the async/await method directly from https://node-postgres.com/guides/async-express.
I've also came across a thread for koa-router where people were having issues with async await calls because of some middle-ware they added that wasn't synchronous
https://github.com/ZijianHe/koa-router/issues/358.
I'm not sure what middle-ware would cause this but here's my app.js that initializes all middle-ware:
var createError = require('http-errors');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require("cors");
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var dataRouter = require("./routes/data");
var uploadRouter = require("./routes/upload")
var fundingRouter = require('./routes/chartData/fundingOverview')
var testRouter = require('./routes/test')
var authRouter = require('./routes/auth')
var session = require('express-session')
var MongoStore = require('connect-mongo')(session)
var passport = require('passport')
const config = require('config')
const mongo = config.get('mongo')
const mongoose = require('mongoose')
mongoose.connect(mongo, {
useUnifiedTopology: true,
useNewUrlParser: true,
useFindAndModify: false
}).then(res => {
console.log('connected')
}).catch(err => {
console.log(err)
})
var express = require('express');
const mountRoutes = require('./routes')
var app = express();
const bodyParser = require('body-parser')
app.use(bodyParser.json())
mountRoutes(app)
app.use(cors())
var sessionMiddleWare = session({
secret: 'top session secret',
store: new MongoStore({ mongooseConnection: mongoose.connection }),
resave: true,
saveUninitialized: true,
unset: 'destroy',
cookie: {
httpOnly: false,
maxAge: 1000 * 3600 * 24,
secure: false, // this need to be false if https is not used. Otherwise, cookie will not be sent.
}
})
app.use(sessionMiddleWare)
// Run production React server on Node server
if(process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
// End Run production React Server on Node Server
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({
extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// app.use('/upload', uploadRouter)
// app.use('/', indexRouter);
// app.use('/users', usersRouter);
// app.use('/data', dataRouter)
// app.use('/funding', fundingRouter)
// app.use('/login', usersRouter)
// app.use('/auth', authRouter)
// catch 404 and forward to error handler
// app.use(function(req, res, next) {
// next(createError(404));
// });
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
I'm mounting the routes directly after body parser. That's the only middle-ware that's called before the routes and is required in order for me to get data into the back end.
I'm able to execute that simple query by putting it into a script file and running 'node test.js' (I.E without the router) and it works fine so I know it's not a problem with node-postgre.
I know this is a problem with the call stack not being totally synchronous but I'm confused as to what's not at this point. I even made the axios call on the front-end async/await with no luck (I don't think it was necessary though).
Any guidance would be help a lot.
EDIT:
I created a fresh express skeleton and hooked my front-end to make a call to a route on the new express server with the same code, it worked. It led me to discover the call wasn't being completed because I was running the server with Nodemon. When I start the server using 'yarn start' the async calls get processed correctly. The question now is what in nodemon makes async router calls not work?
You need to finish the request/response cycle in your middleware.
So in your code:
router.get('/', async (req, res) => {
console.log('OK')
try {
const { rows } = await pool.query('Select VERSION()')
console.log(rows)
res.status(200).json(rows)
}
catch(e) {
console.log(e)
res.status(500).json(e)
}
console.log('DONE')
})
So I am scraping a website, and I want it to show the data to innerHTML, and I am having trouble getting it to work. I am trying to use
document.getElementById('results').innerHTML = searchJobs('');
But it's telling me that document is not defined, sorry nooby question but It's easier to ask than be stuck on the same thing for 45 minutes.
Here is the code :
function searchJobs(i) {
const url = axios.get('actualurl')
return fetch(`${url}${i}`)
.then(response => response.text())
.then(res => {
const jobs = [];
const jobsBody = [];
const $ = cheerio.load(res.data);
$('.result').each((index, element) => {
const title = $(element).children('.title').text();
const linkToJob = $(element).children('.title').children('a').attr('href')
const body = $(element).children('.summary').text();
jobs[index] = { title, linkToJob, body };
});
return jobs;
});
}
document.getElementById('results').innerHTML = searchJobs('');
module.exports = searchJobs;
I can get the scraper to console.log just fine.
index route :
const express = require('express');
const router = express.Router();
const scraper = require('../scrapers/scrapers');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
app.js :
const express = require('express'),
path = require('path'),
cookieParser = require('cookie-parser'),
logger = require('morgan'),
puppeteer = require('puppeteer'),
axios = require('axios'),
cheerio = require('cheerio');
es6Renderer = require('express-es6-template-engine');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.engine('html', es6Renderer);
app.set('views', './views');
app.set('view engine', 'html');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
I think the problem is actually in the view which it's basically just this to keep the post short :
<body>
<p id="results"></p>
<script src="/scrapers/scrapers.js" async defer></script>
</body>
I think I understand what you're trying to accomplish. Remove the document.getElementById line from scrapers.js and modify the others like so:
index route:
router.get('/', function(req, res, next) {
res.render('index', { locals: { results: scraper.searchJobs() }});
});
view:
<body>
<p id="results">${results}</p>
</body>
By doing this you're running the scraper on the server inside of node and then using the templating engine to render the results into the HTML prior to sending it down to the browser.
I am writing a new app, and one of the requirements is that I use the "straight" express boilerplate that include bin/www and an app.js.
I normally just merge the two of them for convenience. Now that I can't, I am wondering...
How can I connect to a DB (which is an async operation) from app.js?
What follows is the full app.js. This does NOT work, because as soon as this line happens:
var connection = await mysql.createConnectionP({
The anonymous function returns an unresolved promise. So the assigned "app" is incomplete, since the code to set it effectively hasn't yet run.
What is the best practice to connect asynchronously to a database keeping the app.js/www duo?
I could connect to the database in www, but then I would need to somehow pass the DB value back to app.js -- is that essentially the only way?
var express = require('express')
var path = require('path')
var favicon = require('serve-favicon')
var logger = require('morgan')
var cookieParser = require('cookie-parser')
var bodyParser = require('body-parser')
var promisify = require('util').promisify
var index = require('./routes/index')
var users = require('./routes/users')
var app = express()
var prpl = require('prpl-server')
var jsonreststores = require('jsonreststores')
var mysql = require('mysql')
mysql.createConnectionP = promisify(mysql.createConnection)
console.log("1")
;(async () => {
var connection = await mysql.createConnectionP({
host: 'localhost',
user: 'root',
password: 'ppp',
database: 'sasit'
})
connection.connectP = promisify(connection.connect)
connection.queryP = promisify(connection.query)
connection.endP = promisify(connection.end)
await connection.connectP()
var res = await connection.queryP('SELECT 1 + 1 AS solution')
console.log('The solution is: ', res[0].solution)
await connection.end()
// view engine setup
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'jade')
// uncomment after placing your favicon in /public
// app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(cookieParser())
// app.use(express.static(path.join(__dirname, 'public')));
// app.use('/', index);
// app.use('/users', users);
app.get('/*', prpl.makeHandler('./public/build', {
builds: [
{name: 'es6-unbundled', browserCapabilities: ['es2015', 'push']},
{name: 'es6-bundled', browserCapabilities: ['es2015']},
{name: 'es5-bundled'}
]
}))
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found')
err.status = 404
next(err)
})
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message
res.locals.error = req.app.get('env') === 'development' ? err : {}
// render the error page
res.status(err.status || 500)
res.render('error')
})
})()
module.exports = app